Skip to content

[feat/#278] 공통 여정 관련 UI#280

Merged
sohee6989 merged 37 commits intodevelopfrom
feat/#278-common-quest-ui
Mar 1, 2026
Merged

[feat/#278] 공통 여정 관련 UI#280
sohee6989 merged 37 commits intodevelopfrom
feat/#278-common-quest-ui

Conversation

@znayeonzn
Copy link
Collaborator

@znayeonzn znayeonzn commented Feb 26, 2026

Related issue 🛠

Work Description 📝

  • 공통 여정 퀘스트 돌아보기 UI (다른 사람, 내 답변)
  • SnackBar 컴포넌트 타입 추가
  • 네비 일부 연결

Screenshot 📸

_.mp4
_.mp4

Uncompleted Tasks 😅

  • 뒤로 가기 아이콘 네비 연결
  • 나의 공통 답변 세부 페이지 바텀시트 네비 연결
  • 모달 추가

PR Point 📌

  • 더미데이터 넣어서 UI만 확인할 수 있게끔 했습니다!
    모달 추가는 코리 반영하면서 넣어놓을게요!

  • 이번 PR 실수가 많을 거 같아요 열.코로 많은 지적해주세요 ㅎㅎ

  • 이번 스프린트에서 스낵바 아이콘이 하나 더 추가됐는데요!
    아이콘 타입 이넘 활용해서 넣고, 스낵바 사용하는 모든 화면 수정했습니다 !
    확인 부탁드려요! 🙇‍♀️

image

자잘한 수정 때문에 건든 파일이 많네요.. 여기 부분 위주로 봐주시면 돼요!

트러블 슈팅 💥

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 내 답변 목록·상세 화면 및 답변 관련 하위 화면(내 답변, 답변 상세, 공통 답변) 추가
    • 더보기 바텀시트·상세 탑바·답변 카드·내 답변 카드 등 UI 컴포넌트 추가
    • 스낵바용 타입 기반 시각화(CustomSnackBarType/Visuals) 추가
  • 개선 사항

    • 포스트 옵션 분리(수정/삭제/차단/신고) 및 오버플로우 메뉴 개선
    • 퀘스트 관련 내비게이션 경로 및 콜백 확장/재구성

@znayeonzn znayeonzn self-assigned this Feb 26, 2026
@znayeonzn znayeonzn added 🍒 [FEAT] 새로운 기능 구현 🍥 [UI] UI 작업 🐰 아연 아연 labels Feb 26, 2026
@auto-assign auto-assign bot requested review from fredleeJH and sohee6989 February 26, 2026 10:16
@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

스낵바를 문자열 기반에서 타입 기반(CustomSnackBarType)으로 전환하고, 공통 여정 답변/나의 답변 검토 기능과 관련 네비게이션(답변 목록/상세/공통답변)을 추가·확장했습니다.

Changes

Cohort / File(s) Summary
스낵바 타입 시스템
app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBar.kt, app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt, app/src/main/java/com/byeboo/app/core/designsystem/event/SnackbarTrigger.kt, app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt
새로운 CustomSnackBarType 추가(ALERT, SUCCESS) 및 기존 문자열 기반 스낵바 API를 타입 기반으로 변경(컴포저블, visuals, compositionLocal 변경).
전역 스낵바 호출자 변환
app/src/main/java/com/byeboo/app/presentation/**/**State.kt, **Screen.kt, **ViewModel.kt (다수)`
프로젝트 전반의 ShowSnackBar 사이드이펙트/호출 위치를 message: StringsnackBarType: CustomSnackBarType로 일괄 마이그레이션(여러 ViewModel과 Screen에서 호출 변경).
메인 네비게이션 확장
app/src/main/java/com/byeboo/app/presentation/main/MainNavHost.kt, MainNavigator.kt, MainScreen.kt
questGraph API 변경: navigateToQuestCommon 제거 및 navigateToQuestCommonWriting, navigateToQuestCommonAnswer(answerId), navigateToQuestMyAnswers(), navigateToQuestMyAnswerDetail(answerId) 등 추가. MainScreen의 onShowSnackBar 시그니처도 업데이트.
퀘스트 네비게이션 및 라우트
app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt, QuestRoute.kt, common/navigation/QuestCommonNavigation.kt
새로운 라우트(QuestCommonAnswer, QuestMyAnswers, QuestMyAnswersDetail) 추가, NavController 확장 함수 추가, 기존 navigateToQuestCommon → navigateToQuestCommonWriting으로 이름 변경.
공통 답변(리뷰) 기능 추가
app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt, CommonAnswerState.kt, CommonAnswerViewModel.kt
공통 여정 답변 상세 화면, 상태 및 ViewModel 추가; 차단/신고 옵션 바텀시트 및 스낵바/네비게이션 사이드이펙트 처리 포함.
나의 답변(리뷰) 기능 추가
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt, MyAnswerState.kt, MyAnswerViewModel.kt, MyAnswerDetailScreen.kt
나의 답변 목록·상세 화면, 상태 및 ViewModel 추가(더보기 바텀시트, 항목 클릭 네비게이션).
퀘스트 UI 컴포넌트 및 타입 변경
app/src/main/java/com/byeboo/app/presentation/quest/component/.../CommonAnswerItem.kt, MyAnswerItem.kt, bottomsheet/MoreOptionsBottomSheet.kt, type/OptionType.kt, component/AnswerDetailTopBar.kt
CommonAnswerItem에 확장/클릭 지원 추가, MyAnswerItem/AnswerDetailTopBar/MoreOptionsBottomSheet 추가, PostOption 인터페이스와 MyPostOption/OtherPostOption enum 도입.
모델 확장
app/src/main/java/com/byeboo/app/presentation/quest/model/QuestModel.kt, QuestState.kt
새로운 MyAnswerModel 추가, QuestSideEffect에 NavigateToQuestMyAnswers 등 네비게이션 효과 추가 및 NavigateToQuestCommon → NavigateToQuestCommonWriting 이름 변경.
리소스 추가
app/src/main/res/drawable/ic_block.xml, ic_overflow_menu.xml, ic_report.xml, ic_success.xml, ic_trash.xml
차단·오버플로우·신고·성공·휴지통 아이콘 벡터 리소스 추가.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant UI as CommonAnswerRoute (UI)
  participant VM as CommonAnswerViewModel
  participant Nav as NavController
  participant Snack as LocalSnackBarTrigger

  User->>UI: 더보기/옵션 선택
  UI->>VM: onClickMoreOptions()/onOptionClicked(option)
  VM-->>UI: uiState 업데이트(showBottomSheet)
  VM->>VM: 처리 (BLOCK/REPORT)
  VM-->>Snack: emit ShowSnackBar(snackBarType)
  alt Navigate after action
    VM-->>Nav: emit NavigateToQuest
  end
  Snack->>UI: render via CustomSnackBarVisuals -> CustomSnackBar
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • #155: CustomSnackBar/Visuals 및 문자열→타입 스낵바 마이그레이션 관련 변경과 직접 연관(스낵바 타입 통합).
  • #43: Quest 네비게이션 및 Quest 관련 화면/뷰모델 변경과 겹침(네비게이션 API 확장 관련).
  • #140: MyPage 스낵바/상태 변경 관련—스낵바 페이로드 타입 전환과 코드 레벨 충돌 가능.

Suggested reviewers

  • znayeonzn
  • fredleeJH

Poem

🐰 토끼가 깡충, 코드 숲을 건너가네
새 알림엔 이름이 붙고 아이콘도 빛나네 ✨
답변을 모으고 길을 넓히며
바텀시트로 불순물을 훌훌 털어내고
ByeBoo 여정, 한 단계 더 폴짝! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 작업의 주요 변경사항을 명확히 반영하고 있으며, 공통 여정 관련 UI 구현이라는 핵심 내용을 간결하게 표현하고 있습니다.
Description check ✅ Passed PR 설명이 필수 섹션(관련 이슈, 작업 설명, 스크린샷, 미완료 작업, PR 포인트, 트러블슈팅)을 포함하고 있으며, 구현 내용을 충분히 기술하고 있습니다.
Linked Issues check ✅ Passed PR은 이슈 #278의 모든 주요 요구사항을 충족하고 있습니다: 공통 여정 답변 UI 구현, 차단/신고 바텀시트 구현, 나의 답변 확인 UI 제공, SnackBar 컴포넌트 개선.
Out of Scope Changes check ✅ Passed 변경사항들이 모두 #278 이슈 범위 내에 있으며, SnackBar 타입 개선과 관련 화면 수정은 공통 여정 UI 구현의 필수 부분입니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#278-common-quest-ui

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt (1)

186-193: ⚠️ Potential issue | 🔴 Critical

onAnswerClick에 하드코딩된 값 1이 전달되고 있습니다.

현재 onAnswerClick(1)로 하드코딩되어 있어, 어떤 답변 항목을 클릭해도 항상 answerId가 1로 전달됩니다. 실제 답변의 ID를 전달해야 합니다.

🐛 수정 제안
                 items(
                     items = state.answers,
                     key = { it.answerId },
                 ) { answer ->
                     CommonAnswerItem(
                         answer = answer,
-                        onClick = { onAnswerClick(1) },
+                        onClick = { onAnswerClick(answer.answerId) },
                         modifier =
                             Modifier
                                 .padding(horizontal = screenWidthDp(24.dp))
                                 .padding(bottom = screenHeightDp(24.dp)),
                     )
                 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt`
around lines 186 - 193, The onClick for CommonAnswerItem is passing a hardcoded
1 to onAnswerClick; change it to pass the clicked answer's ID (e.g., use
answer.id or answer.answerId depending on the model) so the real answer
identifier is forwarded to onAnswerClick; update the onClick lambda in
CommonAnswerItem to call onAnswerClick with the answer's id property (and add a
null/exists check if the model uses a nullable id).
🧹 Nitpick comments (13)
app/src/main/res/drawable/ic_report.xml (1)

10-26: 색상 하드코딩 대신 색상 리소스 참조로 바꾸는 것을 권장합니다.

#FF3B3E가 여러 path에 중복되어 있어 추후 테마 대응(다크모드/브랜드 컬러 변경) 시 유지보수 비용이 커집니다. @color/...로 추출해 공통 관리하는 편이 안전합니다.

♻️ 제안 diff
-        android:strokeColor="#FF3B3E"/>
+        android:strokeColor="@color/snackbar_alert_icon"/>

-        android:strokeColor="#FF3B3E"
+        android:strokeColor="@color/snackbar_alert_icon"

-        android:fillColor="#FF3B3E"/>
+        android:fillColor="@color/snackbar_alert_icon"/>

-        android:fillColor="#FF3B3E"/>
+        android:fillColor="@color/snackbar_alert_icon"/>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/res/drawable/ic_report.xml` around lines 10 - 26, 해당 XML의 여러
path 요소(android:strokeColor 및 android:fillColor)에 하드코딩된 색상값 "#FF3B3E"가 중복되어 있으니
colors.xml에 예: <color name="ic_report_tint">#FF3B3E</color> 같은 리소스를 추가한 뒤
ic_report.xml의 모든 android:strokeColor 및 android:fillColor="#FF3B3E"를
`@color/ic_report_tint로` 교체하세요; 변경 대상 식별에는 각 <path> 요소의 android:pathData 값(예:
"M18,16H6V9.538...", "M4,20L20,20", "M12.005,6.5...", "M12,12.5m-1,0...")과 속성
이름(strokeColor, fillColor)을 참고하면 됩니다.
app/src/main/res/drawable/ic_overflow_menu.xml (1)

1-9: 전반적으로 LGTM, 색상 리소스 사용 고려 권장

벡터 드로어블 구조와 아이콘 형태는 적절합니다. 다만 fillColor#ffffff로 하드코딩되어 있어 다크/라이트 테마 지원이나 다른 배경에서의 재사용성이 제한될 수 있습니다.

스낵바 등 특정 UI에서만 사용될 경우 현재 구현도 무방하지만, 향후 유연성을 위해 색상 리소스나 테마 속성 사용을 고려해 보세요.

♻️ 색상 리소스 사용 제안
  <path
      android:pathData="M12,16.5C12.398,16.5 12.779,16.658 13.061,16.939C13.342,17.221 13.5,17.602 13.5,18C13.5,18.398 13.342,18.779 13.061,19.061C12.779,19.342 12.398,19.5 12,19.5C11.602,19.5 11.221,19.342 10.939,19.061C10.658,18.779 10.5,18.398 10.5,18C10.5,17.602 10.658,17.221 10.939,16.939C11.221,16.658 11.602,16.5 12,16.5ZM12,10.5C12.398,10.5 12.779,10.658 13.061,10.939C13.342,11.221 13.5,11.602 13.5,12C13.5,12.398 13.342,12.779 13.061,13.061C12.779,13.342 12.398,13.5 12,13.5C11.602,13.5 11.221,13.342 10.939,13.061C10.658,12.779 10.5,12.398 10.5,12C10.5,11.602 10.658,11.221 10.939,10.939C11.221,10.658 11.602,10.5 12,10.5ZM12,4.5C12.398,4.5 12.779,4.658 13.061,4.939C13.342,5.221 13.5,5.602 13.5,6C13.5,6.398 13.342,6.779 13.061,7.061C12.779,7.342 12.398,7.5 12,7.5C11.602,7.5 11.221,7.342 10.939,7.061C10.658,6.779 10.5,6.398 10.5,6C10.5,5.602 10.658,5.221 10.939,4.939C11.221,4.658 11.602,4.5 12,4.5Z"
-      android:fillColor="#ffffff"/>
+      android:fillColor="@color/white"/>
</vector>

또는 런타임에 ImageView.setColorFilter() 또는 app:tint를 사용하여 아이콘 색상을 동적으로 적용하는 방법도 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/res/drawable/ic_overflow_menu.xml` around lines 1 - 9, Replace
the hardcoded android:fillColor="#ffffff" in the <path> of the vector drawable
with a color resource or theme attribute so the icon follows dark/light themes
and can be reused; e.g. change android:fillColor to a reference like
`@color/overflow_icon` or a theme attribute like ?attr/colorOnSurface (or make the
vector tintable and remove the fillColor so callers can set app:tint or
ImageView.setColorFilter), update the color resource if needed, and ensure
usages apply the intended tint/theme attribute.
app/src/main/res/drawable/ic_block.xml (1)

6-8: clip-path는 제거해도 동일하게 동작합니다.

Line 7-8은 전체 캔버스를 그대로 클리핑해서 렌더링 결과 변화가 없습니다. 단순화를 위해 제거를 권장합니다.

Diff 제안
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
-  <group>
-    <clip-path
-        android:pathData="M0,0h24v24h-24z"/>
     <path
         android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"
         android:strokeWidth="2"
         android:fillColor="#00000000"
         android:strokeColor="#ffffff"/>
     <path
         android:pathData="M6.327,17.26L17.327,7.26"
         android:strokeWidth="2"
         android:fillColor="#00000000"
         android:strokeColor="#ffffff"/>
-  </group>
 </vector>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/res/drawable/ic_block.xml` around lines 6 - 8, SVG/XML contains
an unnecessary clip-path that clips the whole canvas (the <clip-path> element
with android:pathData="M0,0h24v24h-24z"); remove that <clip-path> element (and
its enclosing empty group if it becomes redundant) from ic_block.xml so the
drawable is simplified without changing rendering.
app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt (1)

60-60: Spacer에 padding 대신 height 사용 필요

Line 60에서 Spacerpadding을 사용하고 있습니다. padding은 모든 방향에 여백을 추가하므로 의도한 12dp가 아닌 24dp(위아래 합산)의 수직 공간이 생깁니다. Line 70처럼 height를 사용해야 합니다.

♻️ 수정 제안
-        Spacer(modifier = Modifier.padding(screenHeightDp(12.dp)))
+        Spacer(modifier = Modifier.height(screenHeightDp(12.dp)))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt`
at line 60, In MyAnswerItem (file MyAnswerItem.kt) the Spacer uses
Modifier.padding(screenHeightDp(12.dp)) which adds padding both top and bottom
(totaling 24dp) instead of providing a 12dp vertical gap; change the Spacer's
modifier to Modifier.height(screenHeightDp(12.dp)) so it produces the intended
12dp vertical space (refer to the Spacer instance around the commented line and
mirror the approach used later on line 70).
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt (1)

84-90: 불필요한 viewModelScope.launch 블록

현재 when 블록 내에 suspend 함수 호출이 없어 viewModelScope.launch가 불필요합니다. TODO 구현 시 실제 비동기 작업이 추가되면 필요하겠지만, 현재로서는 제거하거나 실제 구현 시 추가하는 것이 더 명확합니다.

♻️ 선택적 수정 제안
     fun onOptionClick(option: OptionType) {
         onDismissBottomSheet()

-        viewModelScope.launch {
-            when (option) {
-                OptionType.EDIT -> { /* TODO 수정 화면 이동 */ }
-                OptionType.DELETE -> { /* TODO 삭제 모달 띄우기 */ }
-                else -> {}
-            }
+        when (option) {
+            OptionType.EDIT -> { /* TODO 수정 화면 이동 */ }
+            OptionType.DELETE -> { /* TODO 삭제 모달 띄우기 */ }
+            else -> {}
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`
around lines 84 - 90, The current viewModelScope.launch wrapper around the
when(option) block is unnecessary because there are no suspend calls; remove the
viewModelScope.launch call and execute the when(option) directly (retaining the
OptionType.EDIT and OptionType.DELETE branches) and only reintroduce
viewModelScope.launch around the when when you implement actual asynchronous
work for those branches (or make the called functions suspend and keep the
launch). Refer to the viewModelScope.launch and the when(option) handling
OptionType.EDIT / OptionType.DELETE in MyAnswerViewModel to locate and update
the code.
app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt (1)

60-68: onFailure 내부의 중첩 launch는 제거하는 편이 좋습니다.

이미 viewModelScope.launch 안에서 실행 중이라 _sideEffect.emit(...)을 직접 호출해도 됩니다. 중첩 코루틴을 줄이면 흐름이 단순해집니다.

제안 diff
-                    }.onFailure {
-                        viewModelScope.launch {
-                            _sideEffect.emit(
-                                QuestCompletedSideEffect.ShowSnackBar(
-                                    message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.",
-                                    iconType = CustomSnackBarType.ALERT,
-                                ),
-                            )
-                        }
-                    }
+                    }.onFailure {
+                        _sideEffect.emit(
+                            QuestCompletedSideEffect.ShowSnackBar(
+                                message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.",
+                                iconType = CustomSnackBarType.ALERT,
+                            ),
+                        )
+                    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt`
around lines 60 - 68, In OffboardingQuestCompletedViewModel inside the onFailure
block, remove the nested viewModelScope.launch and directly call
_sideEffect.emit(...) from the surrounding coroutine context (you are already
inside viewModelScope.launch), so replace the inner launch-wrapped emit with a
direct _sideEffect.emit call (keep the same
QuestCompletedSideEffect.ShowSnackBar parameters and CustomSnackBarType.ALERT).
app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.kt (1)

92-95: 동일한 에러 스낵바 emit 로직은 헬퍼로 합치는 것을 권장합니다.

현재 두 실패 분기에서 동일한 블록이 반복되어 유지보수 시 메시지/타입 변경 누락 위험이 있습니다.

♻️ 제안 diff
@@
-                        _sideEffect.emit(
-                            QuestStartSideEffect.ShowSnackBar(
-                                message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.",
-                                iconType = CustomSnackBarType.ALERT,
-                            ),
-                        )
+                        emitServerConnectionErrorSnackBar()
@@
-                        _sideEffect.emit(
-                            QuestStartSideEffect.ShowSnackBar(
-                                message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.",
-                                iconType = CustomSnackBarType.ALERT,
-                            ),
-                        )
+                        emitServerConnectionErrorSnackBar()
@@
+        private suspend fun emitServerConnectionErrorSnackBar() {
+            _sideEffect.emit(
+                QuestStartSideEffect.ShowSnackBar(
+                    message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.",
+                    iconType = CustomSnackBarType.ALERT,
+                ),
+            )
+        }

Also applies to: 132-135

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.kt`
around lines 92 - 95, Duplicate ShowSnackBar emission with the same message/type
is repeated in QuestStartViewModel (the QuestStartSideEffect.ShowSnackBar blocks
at the two failure branches around the existing emits), so extract a single
helper method (e.g., emitServerConnectionSnackBar or emitErrorSnackBar) inside
QuestStartViewModel that constructs/emits QuestStartSideEffect.ShowSnackBar with
the shared message and CustomSnackBarType.ALERT, then replace both duplicated
blocks (the ones around lines 92-95 and 132-135) with calls to that helper to
centralize the message/type and avoid drift.
app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt (1)

7-13: 구현이 올바르며, data class 사용을 고려해 볼 수 있습니다.

SnackbarVisuals 인터페이스 구현이 적절합니다. 선택적으로 data class로 변경하면 equals, hashCode, copy 메서드를 자동으로 얻을 수 있어 테스트나 비교 시 유용할 수 있습니다.

♻️ data class로 변경 제안
-class CustomSnackBarVisuals(
+data class CustomSnackBarVisuals(
     override val message: String,
     val type: CustomSnackBarType,
     override val actionLabel: String? = null,
     override val withDismissAction: Boolean = false,
     override val duration: SnackbarDuration = SnackbarDuration.Short,
 ) : SnackbarVisuals
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt`
around lines 7 - 13, Convert the CustomSnackBarVisuals class into a data class
to automatically get equals/hashCode/copy/toString for easier testing and
comparisons; update the declaration of CustomSnackBarVisuals (which implements
SnackbarVisuals and references CustomSnackBarType, message, actionLabel,
withDismissAction, duration) so it is declared as a data class while keeping the
same primary constructor parameters and the implemented interface
SnackbarVisuals.
app/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.kt (1)

6-29: 하드코딩된 문자열을 string resource로 이동하는 것을 고려해 주세요.

optionTitle 값들이 직접 하드코딩되어 있습니다. 향후 다국어 지원(i18n)을 위해 string resource로 관리하는 것이 좋습니다.

♻️ String resource 사용 제안
 enum class OptionType(
     `@DrawableRes` val optionIcon: Int,
-    val optionTitle: String,
+    `@StringRes` val optionTitleRes: Int,
 ) {
     BLOCK(
         optionIcon = R.drawable.ic_block,
-        optionTitle = "사용자 차단하기",
+        optionTitleRes = R.string.option_block_user,
     ),
     // ... 나머지 항목도 동일하게 적용
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.kt`
around lines 6 - 29, The enum OptionType currently hardcodes Korean titles in
the optionTitle property for entries BLOCK, REPORT, EDIT, DELETE; change
optionTitle to reference string resources instead (e.g., R.string.option_block,
R.string.option_report, R.string.option_edit, R.string.option_delete) and update
callers to resolve the string via Context or a string provider when displaying
(keep the enum values as resource IDs or store `@StringRes` ints rather than raw
Strings). Ensure you add the corresponding entries to strings.xml and mark
optionTitle as an Int annotated with `@StringRes` in the OptionType class.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt (1)

122-126: 뒤로 가기 버튼이 비활성화 상태입니다.

PR 목표에서 "뒤로 가기 아이콘 네비 연결"이 미완료 항목으로 언급되어 있습니다. navigateUp 콜백을 MyAnswerDetailRoute에 추가하고 연결해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`
around lines 122 - 126, Add a navigateUp callback to the MyAnswerDetailRoute and
wire it to the back icon's click handler: update the MyAnswerDetailRoute
signature to accept a navigateUp: () -> Unit parameter, pass that down to
MyAnswerDetailScreen, and replace the TODO in the Modifier.noRippleClickable
used for the back icon so it calls navigateUp() when clicked; ensure any callers
of MyAnswerDetailRoute provide the appropriate NavController::navigateUp or
equivalent lambda.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt (1)

129-133: 뒤로 가기 버튼 클릭 핸들러가 누락되었습니다.

PR 목표에서 "뒤로 가기 아이콘 네비 연결"이 미완료 항목으로 언급되어 있습니다. 이후 작업 시 navigateUp 또는 navigateToQuest 콜백을 연결해야 합니다.

이 기능을 구현하기 위한 코드를 생성해 드릴까요, 아니면 추적을 위한 이슈를 생성할까요?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`
around lines 129 - 133, The back icon currently lacks a click handler; wrap the
Icon in a clickable surface (e.g., IconButton or Modifier.clickable) and invoke
the appropriate navigation callback passed into CommonAnswerScreen (use the
existing navigateUp or navigateToQuest parameter/name) to perform navigation
when tapped; ensure the click target uses the same tint and accessibility by
keeping contentDescription non-null (e.g., "Back") so TalkBack users get the
action.
app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt (1)

85-92: 일관성을 위해 screenHeightDp 사용을 고려해 주세요.

다른 부분에서는 screenHeightDp/screenWidthDp를 사용하여 반응형 레이아웃을 구현하고 있는데, HorizontalDividerpadding(vertical = 20.dp)에서는 하드코딩된 값을 사용하고 있습니다.

♻️ 수정 제안
                 HorizontalDivider(
                     modifier =
                         Modifier
                             .fillMaxWidth()
-                            .padding(vertical = 20.dp),
+                            .padding(vertical = screenHeightDp(20.dp)),
                     thickness = 1.dp,
                     color = ByeBooTheme.colors.gray800,
                 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt`
around lines 85 - 92, Replace the hardcoded Vertical padding on
HorizontalDivider in MoreOptionsBottomSheet (the Modifier.padding(vertical =
20.dp) call) with a responsive value derived from the existing
screenHeightDp/screenWidthDp approach used in this file; compute the vertical
padding from screenHeightDp (using the same scale factor pattern used elsewhere)
and apply that computed value to Modifier.padding so the divider spacing scales
with screen size.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt (1)

88-92: 뒤로 가기 버튼이 비활성화 상태입니다.

noRippleClickable에 클릭 핸들러가 없어 뒤로 가기 아이콘이 동작하지 않습니다. TODO 주석이 있으니 이후 네비게이션 연결이 필요합니다.

이 기능을 구현하는 코드를 생성해 드릴까요?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`
around lines 88 - 92, The back button is non-functional because
Modifier.noRippleClickable has no onClick handler; in MyAnswerScreen replace the
TODO with a lambda that performs navigation (e.g., Modifier.noRippleClickable {
navController.popBackStack() } ) or, if NavController isn't available in this
composable, add an onBackPressed/onNavigateUp: ()->Unit parameter to
MyAnswerScreen and call that inside the noRippleClickable lambda
(Modifier.noRippleClickable { onBackPressed() }) so the icon actually navigates
back.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt`:
- Line 76: The Spacer uses Modifier.padding(end = screenWidthDp(12.dp)) which
doesn't create horizontal space; replace the padding modifier with a width
modifier so the Spacer actually occupies horizontal gap (change Spacer(...
Modifier.padding(end = screenWidthDp(12.dp))) to use
Modifier.width(screenWidthDp(12.dp))) in MoreOptionsBottomSheet (also update the
second occurrence around the other Spacer noted in the comment).

In
`@app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt`:
- Around line 133-137: MyAnswerDetailRoute is not receiving the answerId from
the QuestMyAnswersDetail nav route, so the UI always shows the first answer;
update the navigation composable to pass the route args into the route and
change MyAnswerViewModel to read the answerId from SavedStateHandle (use
savedStateHandle.toRoute<QuestMyAnswersDetail>().answerId) and use that id to
load the specific answer; target symbols: composable<QuestMyAnswersDetail>,
MyAnswerDetailRoute, MyAnswerViewModel, SavedStateHandle, toRoute, answerId.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Around line 147-148: In CommonAnswerScreen.kt the Spacer inside the Row uses
Modifier.padding(bottom = screenHeightDp(16.dp)) which has no effect because Row
lays out children horizontally; either remove the unused Spacer or replace its
modifier to produce the intended spacing: if you wanted horizontal space use
Modifier.width(...), if you wanted vertical space move the Spacer out of the Row
into a Column/parent and use Modifier.height(screenHeightDp(16.dp)) or apply the
bottom padding to the Row or parent container; update the Spacer or parent
accordingly to reflect the intended vertical/horizontal spacing.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`:
- Line 139: The Spacer inside the Row in MyAnswerDetailScreen.kt is using
Modifier.padding(bottom = screenHeightDp(16.dp)), which has no effect in a
horizontal Row; replace that Spacer with a vertical spacing approach by using a
Spacer with Modifier.height(screenHeightDp(16.dp)) or move the bottom padding to
a parent Column/Box that controls vertical spacing (refer to the Spacer instance
and the surrounding Row in MyAnswerDetailScreen.kt and mirror the fix used in
CommonAnswerScreen.kt).
- Line 64: The current code uses uiState.answers.first() which throws
NoSuchElementException for empty lists; change that to a safe access (e.g., use
firstOrNull() or getOrNull(0)) and handle the null case rather than letting it
crash — update the val answerState assignment in MyAnswerDetailScreen to use
uiState.answers.firstOrNull() (or uiState.answers.getOrNull(0)) and then either
early-return, show an empty/error UI, or provide a fallback value so downstream
code using answerState is not executed with a missing item.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`:
- Around line 96-106: The Text composable in MyAnswerScreen currently hardcodes
the nickname string ("하츠핑하츠님의") inside the buildAnnotatedString; replace that
hardcoded text by injecting the real user nickname from the screen state (e.g.,
use uiState.nickname or a value exposed by the ViewModel) when building the
string in the Text composable (the buildAnnotatedString block used for the
header), ensuring you handle null/empty nickname with a sensible fallback.

---

Outside diff comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt`:
- Around line 186-193: The onClick for CommonAnswerItem is passing a hardcoded 1
to onAnswerClick; change it to pass the clicked answer's ID (e.g., use answer.id
or answer.answerId depending on the model) so the real answer identifier is
forwarded to onAnswerClick; update the onClick lambda in CommonAnswerItem to
call onAnswerClick with the answer's id property (and add a null/exists check if
the model uses a nullable id).

---

Nitpick comments:
In
`@app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt`:
- Around line 7-13: Convert the CustomSnackBarVisuals class into a data class to
automatically get equals/hashCode/copy/toString for easier testing and
comparisons; update the declaration of CustomSnackBarVisuals (which implements
SnackbarVisuals and references CustomSnackBarType, message, actionLabel,
withDismissAction, duration) so it is declared as a data class while keeping the
same primary constructor parameters and the implemented interface
SnackbarVisuals.

In
`@app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt`:
- Around line 60-68: In OffboardingQuestCompletedViewModel inside the onFailure
block, remove the nested viewModelScope.launch and directly call
_sideEffect.emit(...) from the surrounding coroutine context (you are already
inside viewModelScope.launch), so replace the inner launch-wrapped emit with a
direct _sideEffect.emit call (keep the same
QuestCompletedSideEffect.ShowSnackBar parameters and CustomSnackBarType.ALERT).

In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt`:
- Around line 85-92: Replace the hardcoded Vertical padding on HorizontalDivider
in MoreOptionsBottomSheet (the Modifier.padding(vertical = 20.dp) call) with a
responsive value derived from the existing screenHeightDp/screenWidthDp approach
used in this file; compute the vertical padding from screenHeightDp (using the
same scale factor pattern used elsewhere) and apply that computed value to
Modifier.padding so the divider spacing scales with screen size.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt`:
- Line 60: In MyAnswerItem (file MyAnswerItem.kt) the Spacer uses
Modifier.padding(screenHeightDp(12.dp)) which adds padding both top and bottom
(totaling 24dp) instead of providing a 12dp vertical gap; change the Spacer's
modifier to Modifier.height(screenHeightDp(12.dp)) so it produces the intended
12dp vertical space (refer to the Spacer instance around the commented line and
mirror the approach used later on line 70).

In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.kt`:
- Around line 6-29: The enum OptionType currently hardcodes Korean titles in the
optionTitle property for entries BLOCK, REPORT, EDIT, DELETE; change optionTitle
to reference string resources instead (e.g., R.string.option_block,
R.string.option_report, R.string.option_edit, R.string.option_delete) and update
callers to resolve the string via Context or a string provider when displaying
(keep the enum values as resource IDs or store `@StringRes` ints rather than raw
Strings). Ensure you add the corresponding entries to strings.xml and mark
optionTitle as an Int annotated with `@StringRes` in the OptionType class.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Around line 129-133: The back icon currently lacks a click handler; wrap the
Icon in a clickable surface (e.g., IconButton or Modifier.clickable) and invoke
the appropriate navigation callback passed into CommonAnswerScreen (use the
existing navigateUp or navigateToQuest parameter/name) to perform navigation
when tapped; ensure the click target uses the same tint and accessibility by
keeping contentDescription non-null (e.g., "Back") so TalkBack users get the
action.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`:
- Around line 122-126: Add a navigateUp callback to the MyAnswerDetailRoute and
wire it to the back icon's click handler: update the MyAnswerDetailRoute
signature to accept a navigateUp: () -> Unit parameter, pass that down to
MyAnswerDetailScreen, and replace the TODO in the Modifier.noRippleClickable
used for the back icon so it calls navigateUp() when clicked; ensure any callers
of MyAnswerDetailRoute provide the appropriate NavController::navigateUp or
equivalent lambda.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`:
- Around line 88-92: The back button is non-functional because
Modifier.noRippleClickable has no onClick handler; in MyAnswerScreen replace the
TODO with a lambda that performs navigation (e.g., Modifier.noRippleClickable {
navController.popBackStack() } ) or, if NavController isn't available in this
composable, add an onBackPressed/onNavigateUp: ()->Unit parameter to
MyAnswerScreen and call that inside the noRippleClickable lambda
(Modifier.noRippleClickable { onBackPressed() }) so the icon actually navigates
back.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`:
- Around line 84-90: The current viewModelScope.launch wrapper around the
when(option) block is unnecessary because there are no suspend calls; remove the
viewModelScope.launch call and execute the when(option) directly (retaining the
OptionType.EDIT and OptionType.DELETE branches) and only reintroduce
viewModelScope.launch around the when when you implement actual asynchronous
work for those branches (or make the called functions suspend and keep the
launch). Refer to the viewModelScope.launch and the when(option) handling
OptionType.EDIT / OptionType.DELETE in MyAnswerViewModel to locate and update
the code.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.kt`:
- Around line 92-95: Duplicate ShowSnackBar emission with the same message/type
is repeated in QuestStartViewModel (the QuestStartSideEffect.ShowSnackBar blocks
at the two failure branches around the existing emits), so extract a single
helper method (e.g., emitServerConnectionSnackBar or emitErrorSnackBar) inside
QuestStartViewModel that constructs/emits QuestStartSideEffect.ShowSnackBar with
the shared message and CustomSnackBarType.ALERT, then replace both duplicated
blocks (the ones around lines 92-95 and 132-135) with calls to that helper to
centralize the message/type and avoid drift.

In `@app/src/main/res/drawable/ic_block.xml`:
- Around line 6-8: SVG/XML contains an unnecessary clip-path that clips the
whole canvas (the <clip-path> element with android:pathData="M0,0h24v24h-24z");
remove that <clip-path> element (and its enclosing empty group if it becomes
redundant) from ic_block.xml so the drawable is simplified without changing
rendering.

In `@app/src/main/res/drawable/ic_overflow_menu.xml`:
- Around line 1-9: Replace the hardcoded android:fillColor="#ffffff" in the
<path> of the vector drawable with a color resource or theme attribute so the
icon follows dark/light themes and can be reused; e.g. change android:fillColor
to a reference like `@color/overflow_icon` or a theme attribute like
?attr/colorOnSurface (or make the vector tintable and remove the fillColor so
callers can set app:tint or ImageView.setColorFilter), update the color resource
if needed, and ensure usages apply the intended tint/theme attribute.

In `@app/src/main/res/drawable/ic_report.xml`:
- Around line 10-26: 해당 XML의 여러 path 요소(android:strokeColor 및
android:fillColor)에 하드코딩된 색상값 "#FF3B3E"가 중복되어 있으니 colors.xml에 예: <color
name="ic_report_tint">#FF3B3E</color> 같은 리소스를 추가한 뒤 ic_report.xml의 모든
android:strokeColor 및 android:fillColor="#FF3B3E"를 `@color/ic_report_tint로` 교체하세요;
변경 대상 식별에는 각 <path> 요소의 android:pathData 값(예: "M18,16H6V9.538...",
"M4,20L20,20", "M12.005,6.5...", "M12,12.5m-1,0...")과 속성 이름(strokeColor,
fillColor)을 참고하면 됩니다.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da5b372 and 2ac162e.

📒 Files selected for processing (82)
  • app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBar.kt
  • app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt
  • app/src/main/java/com/byeboo/app/core/designsystem/event/SnackbarTrigger.kt
  • app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt
  • app/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoState.kt
  • app/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/home/HomeScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/home/HomeUiState.kt
  • app/src/main/java/com/byeboo/app/presentation/home/HomeViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletState.kt
  • app/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/main/MainNavHost.kt
  • app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt
  • app/src/main/java/com/byeboo/app/presentation/main/MainScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/MyPageScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/MyPageState.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/MypageViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersState.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileState.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/OffboardingJourneyState.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/OffboardingJourneyViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideState.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedjourney/OffboardingCompletedJourneyScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedState.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorWritingScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/card/CommonAnswerItem.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/model/QuestModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestRoute.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/splash/SplashScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/splash/SplashState.kt
  • app/src/main/java/com/byeboo/app/presentation/splash/SplashViewModel.kt
  • app/src/main/res/drawable/ic_block.xml
  • app/src/main/res/drawable/ic_overflow_menu.xml
  • app/src/main/res/drawable/ic_report.xml
  • app/src/main/res/drawable/ic_success.xml
  • app/src/main/res/drawable/ic_trash.xml

Comment on lines +133 to +137
composable<QuestMyAnswersDetail> {
MyAnswerDetailRoute(
paddingValues = paddingValues,
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find MyAnswerDetailRoute implementation
fd -t f "MyAnswerDetailRoute" --type f

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 57


🏁 Script executed:

# Search for MyAnswerDetailRoute function/composable definition
rg -n "fun MyAnswerDetailRoute|@Composable.*MyAnswerDetailRoute" --type=kotlin

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 201


🏁 Script executed:

# Find MyAnswerViewModel file
fd -t f "*MyAnswerViewModel*" --type f

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 373


🏁 Script executed:

# Check MyAnswerViewModel constructor and SavedStateHandle usage
rg -n "class MyAnswerViewModel|SavedStateHandle|answerId" --type=kotlin -B 2 -A 5 | grep -A 20 "MyAnswerViewModel"

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 8822


🏁 Script executed:

# Read MyAnswerDetailRoute implementation
cat -n app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt | head -80

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 3779


🏁 Script executed:

# Read the full MyAnswerViewModel to see all details
cat -n app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 4635


🏁 Script executed:

# Search for QuestMyAnswersDetail route definition in QuestNavigation
rg -n "QuestMyAnswersDetail" app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt -B 2 -A 2

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 346


MyAnswerDetailRouteQuestMyAnswersDetail 라우트로부터 answerId를 수신하지 않습니다.

네비게이션에서 QuestMyAnswersDetail(answerId)로 이동하지만, MyAnswerDetailRoute는 이 파라미터를 받지 않습니다. 현재 구현에서는 uiState.answers.first()를 사용하므로 항상 첫 번째 답변만 표시됩니다.

MyAnswerViewModel에서 SavedStateHandle을 주입받아 라우트 파라미터로부터 answerId를 추출하도록 수정해야 합니다:

class MyAnswerViewModel
    `@Inject`
    constructor(
        private val savedStateHandle: SavedStateHandle,
    ) : ViewModel() {
        private val answerId: Long = savedStateHandle.toRoute<QuestMyAnswersDetail>().answerId
        // ... answerId를 사용하여 해당 답변 조회
    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt`
around lines 133 - 137, MyAnswerDetailRoute is not receiving the answerId from
the QuestMyAnswersDetail nav route, so the UI always shows the first answer;
update the navigation composable to pass the route args into the route and
change MyAnswerViewModel to read the answerId from SavedStateHandle (use
savedStateHandle.toRoute<QuestMyAnswersDetail>().answerId) and use that id to
load the specific answer; target symbols: composable<QuestMyAnswersDetail>,
MyAnswerDetailRoute, MyAnswerViewModel, SavedStateHandle, toRoute, answerId.

modifier: Modifier = Modifier,
) {
val scrollState = rememberScrollState()
val answerState = uiState.answers.first()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

uiState.answers.first()는 빈 리스트에서 NoSuchElementException을 발생시킵니다.

answers 리스트가 비어있을 경우 앱이 크래시됩니다. 안전한 접근 방식을 사용하거나 빈 상태를 처리해야 합니다.

🐛 수정 제안
 `@Composable`
 private fun MyAnswerDetailScreen(
     uiState: MyAnswerState,
     paddingValues: PaddingValues,
     onClickMoreOptions: () -> Unit,
     onDismissBottomSheet: () -> Unit,
     onOptionClick: (OptionType) -> Unit,
     modifier: Modifier = Modifier,
 ) {
     val scrollState = rememberScrollState()
-    val answerState = uiState.answers.first()
+    val answerState = uiState.answers.firstOrNull() ?: return
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val answerState = uiState.answers.first()
`@Composable`
private fun MyAnswerDetailScreen(
uiState: MyAnswerState,
paddingValues: PaddingValues,
onClickMoreOptions: () -> Unit,
onDismissBottomSheet: () -> Unit,
onOptionClick: (OptionType) -> Unit,
modifier: Modifier = Modifier,
) {
val scrollState = rememberScrollState()
val answerState = uiState.answers.firstOrNull() ?: return
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`
at line 64, The current code uses uiState.answers.first() which throws
NoSuchElementException for empty lists; change that to a safe access (e.g., use
firstOrNull() or getOrNull(0)) and handle the null case rather than letting it
crash — update the val answerState assignment in MyAnswerDetailScreen to use
uiState.answers.firstOrNull() (or uiState.answers.getOrNull(0)) and then either
early-return, show an empty/error UI, or provide a fallback value so downstream
code using answerState is not executed with a missing item.

Comment on lines 96 to 106
Text(
text =
buildAnnotatedString {
append("하츠핑하츠님의")
append("\n")
append("공통퀘스트 답변이에요")
},
color = ByeBooTheme.colors.gray50,
style = ByeBooTheme.typography.head2,
modifier = Modifier.padding(vertical = screenHeightDp(10.dp)),
)
Copy link

@coderabbitai coderabbitai bot Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

닉네임이 하드코딩되어 있습니다.

"하츠핑하츠님의"가 하드코딩되어 있습니다. 실제 사용자 닉네임은 uiState에서 가져오거나 ViewModel을 통해 주입받아야 합니다.

🔧 수정 제안
                 Text(
                     text =
                         buildAnnotatedString {
-                            append("하츠핑하츠님의")
+                            append("${uiState.nickname}님의")
                             append("\n")
                             append("공통퀘스트 답변이에요")
                         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`
around lines 96 - 106, The Text composable in MyAnswerScreen currently hardcodes
the nickname string ("하츠핑하츠님의") inside the buildAnnotatedString; replace that
hardcoded text by injecting the real user nickname from the screen state (e.g.,
use uiState.nickname or a value exposed by the ViewModel) when building the
string in the Text composable (the buildAnnotatedString block used for the
header), ensuring you handle null/empty nickname with a sensible fallback.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@znayeonzn 반영 부탁드립니다!
닉네임 파라미터로 받아야 될 것 같아요

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Collaborator

@fredleeJH fredleeJH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생 많으셨습니다!


@Composable
private fun MyAnswerDetailTopBar(
onClickMoreOptions: () -> Unit,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 탑 바를 공통 컴포넌트로 빼는건 별로일까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영하겠습니다!!

modifier = modifier,
)

QuestTitle(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공통퀘스트는 피그마상 타이틀이 조금 다른데 같은데 확인 부탁 드립니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 아직 이전 pr 병합을 못해서 일단 이렇게 썼습니다!
추후에 풀 받아온 후 수정하겠습니다!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt (1)

19-23: 뒤로가기 콜백 파라미터 누락

현재 onClickMoreOptions만 파라미터로 받고 있지만, 뒤로가기 아이콘도 클릭 가능한 상태입니다(Line 36-38). 재사용성과 완성도를 위해 onClickBack 콜백도 추가하는 것이 좋습니다.

♻️ 제안: onClickBack 파라미터 추가
 `@Composable`
 fun AnswerDetailTopBar(
+    onClickBack: () -> Unit,
     onClickMoreOptions: () -> Unit,
     modifier: Modifier = Modifier,
 ) {

그리고 Line 36-38의 noRippleClickable에 적용:

             modifier =
                 Modifier.noRippleClickable(
-                    // Todo: 뒤로가기
+                    onClick = onClickBack,
                 ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`
around lines 19 - 23, Add a missing back-click callback to the
AnswerDetailTopBar composable by introducing an onClickBack: () -> Unit
parameter (with a sensible default if desired) alongside the existing
onClickMoreOptions; then update the back icon's noRippleClickable invocation
(the click handler around the Back icon in AnswerDetailTopBar) to call
onClickBack instead of being hardcoded/absent so back presses are handled by the
caller.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Around line 82-85: CommonAnswerScreen currently forwards its incoming modifier
to AnswerDetailTopBar even though that modifier is already applied to the parent
Column (see Column in CommonAnswerScreen); change the call to AnswerDetailTopBar
to pass a fresh/empty Modifier (or omit the modifier argument if optional)
instead of the external modifier to avoid double-applying the same modifier;
update the invocation of AnswerDetailTopBar in CommonAnswerScreen and ensure any
local styling needed by AnswerDetailTopBar is provided via a dedicated internal
modifier rather than the external parameter.
- Line 94: Spacer에 Modifier.padding(bottom = ...)를 사용하면 의도한 수직 간격이 적용되지 않으므로, 해당
Spacer 호출(함수/파일의 Spacer(...) 사용 부분)에서 Modifier.padding을 제거하고 대신
Modifier.height(screenHeightDp(10.dp))로 크기를 지정해 수직 여백을 명시적으로 적용하도록 변경하세요; 즉 현재의
Spacer(modifier = Modifier.padding(bottom = screenHeightDp(10.dp)))를
Spacer(modifier = Modifier.height(screenHeightDp(10.dp)))로 바꾸면 됩니다.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`:
- Around line 31-38: Two Icon composables currently set contentDescription =
null (e.g., the Icon using ImageVector.vectorResource(id = R.drawable.ic_left)
with Modifier.noRippleClickable) which prevents screen readers from conveying
the button purpose; update both Icon usages (the left/back Icon and the other
Icon in the 43-52 range) to provide meaningful, localized contentDescription
strings (use string resources like R.string.back or R.string.edit/action_name)
instead of null, and only keep null if the icon is purely decorative; ensure the
descriptions match the button action invoked by the surrounding clickable
(Modifier.noRippleClickable) so accessibility tools read the correct intent.

---

Nitpick comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`:
- Around line 19-23: Add a missing back-click callback to the AnswerDetailTopBar
composable by introducing an onClickBack: () -> Unit parameter (with a sensible
default if desired) alongside the existing onClickMoreOptions; then update the
back icon's noRippleClickable invocation (the click handler around the Back icon
in AnswerDetailTopBar) to call onClickBack instead of being hardcoded/absent so
back presses are handled by the caller.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ac162e and eebf0ca.

📒 Files selected for processing (4)
  • app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt

Comment on lines +31 to +38
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_left),
contentDescription = null,
tint = ByeBooTheme.colors.gray50,
modifier =
Modifier.noRippleClickable(
// Todo: 뒤로가기
),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

접근성: contentDescription 누락

두 아이콘 모두 contentDescription = null로 설정되어 있어 스크린 리더 사용자가 버튼의 용도를 알 수 없습니다.

♿ 제안: contentDescription 추가
         Icon(
             imageVector = ImageVector.vectorResource(id = R.drawable.ic_left),
-            contentDescription = null,
+            contentDescription = "뒤로 가기",
             tint = ByeBooTheme.colors.gray50,
         Icon(
             imageVector = ImageVector.vectorResource(id = R.drawable.ic_overflow_menu),
-            contentDescription = null,
+            contentDescription = "더보기 옵션",
             tint = ByeBooTheme.colors.white,

Also applies to: 43-52

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`
around lines 31 - 38, Two Icon composables currently set contentDescription =
null (e.g., the Icon using ImageVector.vectorResource(id = R.drawable.ic_left)
with Modifier.noRippleClickable) which prevents screen readers from conveying
the button purpose; update both Icon usages (the left/back Icon and the other
Icon in the 43-52 range) to provide meaningful, localized contentDescription
strings (use string resources like R.string.back or R.string.edit/action_name)
instead of null, and only keep null if the icon is purely decorative; ensure the
descriptions match the button action invoked by the surrounding clickable
(Modifier.noRippleClickable) so accessibility tools read the correct intent.

Copy link
Collaborator

@sohee6989 sohee6989 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일차적으로 이것들 먼저 남길게요!

래빗이 리뷰에 태그 달아놓은 것도 확인 부탁드려요!

_sideEffect.emit(
SplashStateSideEffect.ShowSnackBar(
"서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.",
message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: message도 CustomSnackBarType에서 같이 관리하는데 어떠세요?

import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf

data class MyAnswerState(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 저희 data class들에 @immutable 붙이는 건 어떠세요? 전부 val 기반이라 안정성/리컴포지션 측면에서 도움될 것 같아서요!

import androidx.annotation.DrawableRes
import com.byeboo.app.R

enum class OptionType(
Copy link
Collaborator

@sohee6989 sohee6989 Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: 차단/신고와 수정/삭제는 의도와 책임이 다르기 때문에 UI가 같다는 이유로 하나로 묶기보다 도메인 기준으로 나누는 게 더 명확할 것 같다는 생각이 듭니다.
관련해서 의견이 궁금합니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일단 UI 만 고려하고 코드를 짜서 한번에 넣었습니다..ㅎㅎ
소희님 의견대로 도메인 기준으로 나누는 것이
이후 서버 연결까지 고려했을 때 더 나은 거 같습니다! 감사합니다 :)

}
}

fun onMyAnswersClick() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 함수명 다른 것처럼 ~Clicked로 부탁드릴게요!

) { answer ->
CommonAnswerItem(
answer = answer,
onClick = { onAnswerClick(1) },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이것도 TODO 남겨놓는게 좋을 것 같아요!

tint = ByeBooTheme.colors.white,
)

Spacer(modifier = Modifier.width(screenWidthDp(12.dp)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이거 Row에서 주자요~!

tint = ByeBooTheme.colors.error300,
)

Spacer(modifier = Modifier.padding(end = screenWidthDp(12.dp)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이것도요!

modifier =
Modifier
.fillMaxWidth()
.padding(vertical = 20.dp),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: screenHeight 써주자요~

)
}

Spacer(modifier = Modifier.padding(bottom = screenHeightDp(36.dp)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이거 height로 주는거 어떠세요??
.padding(bottom ) 이라는게 모호한 것 같아서요!

)
}

Spacer(modifier = Modifier.padding(screenHeightDp(12.dp)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: height로 통일해서 써주는거 어떠세요??

text = "Q.",
color = ByeBooTheme.colors.primary200,
style = ByeBooTheme.typography.sub2,
modifier = Modifier.padding(end = screenWidthDp(4.dp)),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이거 패딩보다 Row에 간격주는게 더 직관적일 것 같아요!

Comment on lines +53 to +56
Text(
text = answer.question,
color = ByeBooTheme.colors.gray100,
style = ByeBooTheme.typography.sub3,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: 질문 무조건 1줄로 와야될 것 같은데 문장이 긴 질문에 대한 처리 해줘야 될 것 같아요..!
근데 이것 관련해서 화면 설계서에 따로 내용이 없는 것 같아서 확인 한 번 해주셔야 될 것 같습니다~

Comment on lines 31 to 41
modifier
.fillMaxWidth()
.noRippleClickable {
onMyAnswerContentClick(answer.answerId)
}.background(
color = ByeBooTheme.colors.whiteAlpha5,
shape = RoundedCornerShape(12.dp),
).padding(
horizontal = screenWidthDp(24.dp),
vertical = screenHeightDp(16.dp),
),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1: 여기 clip으로 안 해줘서 코너 부분 눌러도 클릭이 되고 있습니다..!

import kotlinx.coroutines.flow.collectLatest

@Composable
fun MyAnswerRoute(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이 화면 같은 경우에는 지금 내용 다 서버에서 받고 있으니 UiState로 화면 분기 처리 해주면 좋을 것 같아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵! 이 부분은 서버 연결하면서 같이 반영하겠습니다!

Comment on lines 36 to 47
modifier =
modifier
.fillMaxWidth()
.background(
.noRippleClickable(
onClick = onClick,
).background(
color = ByeBooTheme.colors.whiteAlpha5,
shape = RoundedCornerShape(12.dp),
).padding(
horizontal = screenWidthDp(24.dp),
vertical = screenHeightDp(16.dp),
),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 여기도 clip 줘야 될 것 같습니다!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: 이거 화면 이름에 All 넣어서 구분해주는거 어떠세요??

questQuestion = "그 사람이 싫어하기에 내가 포기해야만 했던 일은 무엇일까?",
)

Spacer(modifier = Modifier.padding(bottom = screenHeightDp(10.dp)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1: 이거 20인 것 같습니다. 확인 부탁드려요~

),
)

Spacer(modifier = Modifier.padding(bottom = screenHeightDp(16.dp)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이것도 spacer height로 줍시다~

modifier =
Modifier
.fillMaxWidth(),
contentAlignment = Alignment.Center,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1: 이거 위치가 center가 아니예요!


if (uiState.answers.isEmpty()) {
item {
Box(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: 그리고 가로 중앙 정렬을 위해서 밑에 Text에 fillMaxWidth를 써주던가 이거 Box 대신 Column으로 써서 horizonta center 주면 될 것 같습니다

questQuestion = "그 사람이 싫어하기에 내가 포기해야만 했던 일은 무엇일까?",
)

Spacer(modifier = Modifier.padding(bottom = screenHeightDp(10.dp)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이것도 spacer height로 부탁드립니다~!

) {
AnswerDetailTopBar(
onClickMoreOptions = onClickMoreOptions,
modifier = modifier,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이거 modifier 위에서 쓰고 있느거니 여기서 modifier를 넘겨주면 안 될 것 ㅏㄱㅌ습니다.
추가로 여기 지금 modifier 관련 속성 안쓰고 있으니 아예 안 써줘도 될 것 같아요!

),
)

fun onMyAnswerContentClick(answerId: Long) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 여기도 다른 화면들처럼 함수명 Clicked로 부탁드릴게요

import com.byeboo.app.presentation.quest.review.common.component.AnswerDetailTopBar

@Composable
fun MyAnswerDetailRoute(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: 여기도 내용 서버에서 받아오고 있으니 UiState로 관리해주면 좋을 것 같아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서버 연결하면서 반영할게요!

_uiState.update { it.copy(showBottomSheet = false) }
}

fun onOptionClick(option: OptionType) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 여기도 다른 화면들처럼 함수명 Clicked로 부탁드릴게요

Copy link
Collaborator

@sohee6989 sohee6989 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다~~

Comment on lines 8 to 14
CommonAnswerModel(
answerId = -1L,
writer = "사용자닉네",
profileIconRes = -1,
displayTime = "2026-01-30",
content = "헤어진 첫날 밤이었어요. 혼자 집에 있는데 갑자기 모든 게 현실로 다가왔고, 이제 정말 끝났다는 걸 깨달았을 때... 그때가 제일 힘들었던 것 같아요.",
),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: 이거 빈값으로 넣어주는게 낫지 않나요??

Comment on lines 46 to 52
ModalBottomSheet(
onDismissRequest = onDismissRequest,
modifier = modifier,
sheetState = sheetState,
containerColor = ByeBooTheme.colors.gray900,
scrimColor = scrimColor,
dragHandle = null,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p1: 여기 shape 사용해서 radius 12.dp 줘야 될 것 같습니다!

sheetState: SheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
isBackgroundDimmed: Boolean = true,
) {
val scrimColor = if (isBackgroundDimmed) ByeBooTheme.colors.blackAlpha80 else Color.Transparent
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: 이거 지금 scrimColor가 blackAlpha80로 보이는 거니까 분기처리 안해줘도 되지 않나여??

) {
Column(
modifier =
modifier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p2: 이거 Modifier 로 써줘야 될 것 같아요~

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt (1)

59-59: ⚠️ Potential issue | 🔴 Critical

빈 답변 리스트에서 크래시가 발생합니다.

Line 59의 uiState.answers.first()는 데이터가 비어 있으면 NoSuchElementException로 즉시 종료됩니다.

🐛 제안 수정
-    val answerState = uiState.answers.first()
+    val answerState = uiState.answers.firstOrNull() ?: return
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`
at line 59, The code crashes when uiState.answers is empty because
MyAnswerDetailScreen uses uiState.answers.first(); change this to safe access
(e.g., use firstOrNull() or check isEmpty()) and handle the null/empty case
before proceeding: update the answerState assignment to use firstOrNull() and
add a guard (early return, placeholder UI, or error state) in the
MyAnswerDetailScreen rendering logic so downstream code does not assume a
non-null answer.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.kt (1)

6-16: ⚠️ Potential issue | 🟡 Minor

기본값 profileIconRes = 0이 런타임 문제를 일으킬 수 있습니다.

profileIconRes = 0은 유효하지 않은 drawable 리소스 ID입니다. UI에서 이 기본값을 사용하려 할 경우 Resources.NotFoundException이 발생할 수 있습니다. nullable 타입이나 유효한 기본 리소스 사용을 고려해 주세요.

,

💡 제안된 수정
 data class CommonAnswerState(
     val answer: CommonAnswerModel =
         CommonAnswerModel(
             answerId = 0L,
             writer = "",
-            profileIconRes = 0,
+            profileIconRes = R.drawable.ic_profile_default, // 유효한 기본 아이콘 사용
             displayTime = "",
             content = "",
         ),
     val showBottomSheet: Boolean = false,
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.kt`
around lines 6 - 16, The default profileIconRes = 0 is invalid and can throw
Resources.NotFoundException; update CommonAnswerModel.profileIconRes to be safe
by either making it nullable (Int? = null) and adjust all UI consumers to handle
null (e.g., show placeholder when profileIconRes == null) or assign a valid
drawable default (e.g., DEFAULT_PROFILE_ICON) and use that constant in
CommonAnswerState's initializer; touch the CommonAnswerModel declaration and
every place that reads profileIconRes (adapter/binding/Composables) to implement
the chosen null/placeholder handling.
🧹 Nitpick comments (12)
app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt (2)

6-20: SUCCESS 타입에도 아이콘 커스터마이징 고려

현재 SUCCESS는 메시지만 커스터마이징 가능하고 아이콘은 고정되어 있습니다. 향후 다양한 성공 케이스에서 다른 아이콘이 필요할 수 있으니, 확장성을 고려해 두시면 좋겠습니다. 현재 구현으로도 충분히 동작하므로 선택적 개선 사항입니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt`
around lines 6 - 20, Update the SUCCESS subtype to accept an optional icon
parameter so callers can override the icon; change the SUCCESS constructor
signature in CustomSnackBarType to include a `@DrawableRes` icon: Int =
R.drawable.ic_success (or similar default) and pass that icon into the sealed
class primary constructor when constructing SUCCESS, leaving the message
parameter as-is to preserve existing usage.

10-13: 하드코딩된 문자열 대신 문자열 리소스 사용 권장

ALERT 타입의 메시지가 코드에 직접 하드코딩되어 있습니다. 다국어 지원(i18n)과 유지보수를 위해 strings.xml의 문자열 리소스를 사용하는 것이 좋습니다.

♻️ 문자열 리소스 사용 제안

strings.xml에 추가:

<string name="snackbar_server_error">서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.</string>

단, sealed class의 생성자에서는 Context 없이 string resource ID를 직접 사용할 수 없으므로, 다음과 같은 대안을 고려할 수 있습니다:

 sealed class CustomSnackBarType(
     `@DrawableRes` val icon: Int,
-    val message: String,
+    `@StringRes` val messageRes: Int,
 ) {
     object ALERT : CustomSnackBarType(
         icon = R.drawable.ic_alert,
-        message = "서버에 연결할 수 없습니다. 잠시 후 시도해 주세요.",
+        messageRes = R.string.snackbar_server_error,
     )

또는 현재 구조를 유지하고 CustomSnackBar composable에서 Context를 통해 리소스를 가져오는 방식도 가능합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt`
around lines 10 - 13, The ALERT case in CustomSnackBarType currently hardcodes
the message string; add a string resource (e.g., snackbar_server_error) to
strings.xml and stop embedding raw text in CustomSnackBarType.ALERT by either
(A) changing the sealed class to accept a messageResId Int (e.g., add a
parameter messageResId: Int? alongside icon) and set ALERT to messageResId =
R.string.snackbar_server_error, or (B) leave the sealed class unchanged but
remove the hardcoded message (set message = null or empty) and update the
CustomSnackBar composable to resolve the appropriate string via
LocalContext.current.getString(R.string.snackbar_server_error) when rendering
ALERT; pick one approach and apply it consistently (update constructors/usages
of CustomSnackBarType, the ALERT object, and the CustomSnackBar composable to
load the string resource).
app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.kt (1)

66-66: UiState.Failure 처리 누락 확인 필요

실패 상태에서 사용자에게 피드백을 제공하지 않고 있습니다. 에러 스낵바 표시나 에러 UI를 고려해 보세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.kt`
at line 66, BlockedUsersScreen currently ignores UiState.Failure (is
UiState.Failure -> Unit); update the BlockedUsersScreen composable to handle
UiState.Failure by surfacing the error (e.g., show a Snackbar via
Scaffold/rememberSnackbarHostState or render an error UI) and pass the failure
message from the UiState.Failure instance into that UI; modify the state
handling branch that matches UiState.Failure to call
snackbarHostState.showSnackbar(...) or render an ErrorView and ensure the
ViewModel/UiState provides the failure message used for display.
app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt (1)

289-293: 함수명을 onMyAnswersClicked로 변경해주세요.

다른 함수들(onTipClicked, onQuestClicked)과 일관성을 위해 ~Clicked 접미사를 사용해야 합니다.

♻️ 수정 제안
-    fun onMyAnswersClick() {
+    fun onMyAnswersClicked() {
         viewModelScope.launch {
             _sideEffect.emit(QuestSideEffect.NavigateToQuestMyAnswers)
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt` around
lines 289 - 293, Rename the ViewModel method onMyAnswersClick to
onMyAnswersClicked and update all its usages/call sites accordingly (including
any references in XML, navigation, tests, and callers) to keep naming consistent
with onTipClicked and onQuestClicked; preserve the implementation (launching
viewModelScope and emitting QuestSideEffect.NavigateToQuestMyAnswers) and update
any imports or overrides if applicable so compilation remains clean.
app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt (1)

83-90: HorizontalDivider의 padding 적용 방식을 확인해주세요.

Modifier.padding(screenHeightDp(20.dp))는 모든 방향(상하좌우)에 패딩을 적용합니다. Divider 위아래 간격만 주려는 의도라면 vertical 패딩을 사용하는 것이 명확합니다.

♻️ 수정 제안
                 HorizontalDivider(
                     modifier =
                         Modifier
                             .fillMaxWidth()
-                            .padding(screenHeightDp(20.dp)),
+                            .padding(vertical = screenHeightDp(20.dp)),
                     thickness = 1.dp,
                     color = ByeBooTheme.colors.gray800,
                 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt`
around lines 83 - 90, HorizontalDivider currently uses
Modifier.padding(screenHeightDp(20.dp)) which applies padding on all sides;
change it to use vertical padding only so only top/bottom spacing is affected —
update the modifier on HorizontalDivider (the call that currently uses
Modifier.fillMaxWidth().padding(screenHeightDp(20.dp))) to use
Modifier.fillMaxWidth().padding(vertical = screenHeightDp(20.dp)) so left/right
padding is not applied.
app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt (1)

85-93: onMyAnswersClickonMyAnswersClicked로 변경이 필요합니다.

QuestViewModel의 함수명 변경에 맞춰 이 파일의 콜백 파라미터명도 일관되게 onMyAnswersClicked로 변경해주세요. onQuestClickonQuestClicked로, onTipClickonTipClicked로 변경된 것과 동일한 패턴입니다.

♻️ 수정 제안
     QuestScreen(
         uiState = uiState,
         listState = listState,
         paddingValues = paddingValues,
         onQuestClick = viewModel::onQuestClicked,
-        onMyAnswersClick = viewModel::onMyAnswersClick,
+        onMyAnswersClicked = viewModel::onMyAnswersClicked,
         onDismissModal = viewModel::onQuitDismissModal,
         onTipClick = viewModel::onTipClicked,
         onQuestStart = viewModel::onQuestStart,
         onTabClick = viewModel::onTabClicked,
         onCommonAnswerClick = navigateToCommonAnswer,
         onDateChange = viewModel::onDateChange,
     )

QuestScreen 함수 시그니처도 함께 수정:

 private fun QuestScreen(
     uiState: QuestUiState,
     listState: LazyListState,
     paddingValues: PaddingValues,
     onQuestClick: (Long) -> Unit,
-    onMyAnswersClick: () -> Unit,
+    onMyAnswersClicked: () -> Unit,
     onDismissModal: () -> Unit,

Also applies to: 102-102, 156-157

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt` around
lines 85 - 93, The callback name for "my answers" must be renamed to match the
ViewModel change: replace all occurrences of onMyAnswersClick with
onMyAnswersClicked — update the QuestScreen composable parameter name
(QuestScreen(... onMyAnswersClicked: () -> Unit ...)), the call site wiring (use
viewModel::onMyAnswersClicked instead of viewModel::onMyAnswersClick), and any
internal uses/forwarding of onMyAnswersClick (including navigate/handler
passthroughs) to the new onMyAnswersClicked identifier so names are consistent
with onQuestClicked and onTipClicked.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt (1)

81-90: TODO 구현 및 불필요한 코루틴 스코프 정리.

EDIT/DELETE 옵션이 TODO 플레이스홀더로 비어 있습니다. 현재 viewModelScope.launch 블록이 빈 when 분기를 감싸고 있어 불필요합니다. 실제 로직이 추가될 때까지 코루틴 래핑을 제거하거나, 구현이 필요한 경우 알려주세요.

,

💡 현재 상태에서의 간소화 제안
         fun onOptionClicked(option: MyPostOption) {
             onDismissBottomSheet()
 
-            viewModelScope.launch {
-                when (option) {
-                    MyPostOption.EDIT -> { /* TODO 수정 화면 이동 */ }
-                    MyPostOption.DELETE -> { /* TODO 삭제 모달 띄우기 */ }
-                }
+            when (option) {
+                MyPostOption.EDIT -> { /* TODO 수정 화면 이동 */ }
+                MyPostOption.DELETE -> { /* TODO 삭제 모달 띄우기 */ }
             }
         }

EDIT/DELETE 기능 구현을 도와드릴까요?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`
around lines 81 - 90, The onOptionClicked function currently wraps empty TODO
branches in viewModelScope.launch and should be simplified or implemented: if
you don't yet have async work, remove the unnecessary coroutine wrapper and
directly call onDismissBottomSheet and the synchronous handlers for
MyPostOption.EDIT and MyPostOption.DELETE; if you intend to implement behavior
now, replace the TODOs inside onOptionClicked (handling MyPostOption.EDIT to
navigate/open edit screen and MyPostOption.DELETE to show a delete confirmation
modal) and only keep viewModelScope.launch if those handlers perform suspend
work (network/DB); reference the onOptionClicked function and MyPostOption enum
to locate and update the branches accordingly.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt (3)

88-91: 뒤로가기 네비게이션 미구현 상태

TODO 주석이 있고 noRippleClickable에 빈 람다가 전달되고 있습니다. PR 미완성 작업 목록에 "뒤로 가기 아이콘 네비 연결"이 포함되어 있으므로, 추후 구현이 필요합니다.

뒤로가기 네비게이션 구현을 도와드릴까요? navigateUp 콜백을 MyAnswerRoute에 추가하고 연결하는 방식을 제안드릴 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`
around lines 88 - 91, The no-op click handler on the back icon is left as a
TODO; wire up proper navigation by adding a navigateUp: () -> Unit parameter to
MyAnswerRoute (and propagate it into MyAnswerScreen), then replace the empty
lambda passed to Modifier.noRippleClickable with a call to that navigateUp
callback so the back icon triggers navigation (ensure MyAnswerRoute caller
supplies navController::navigateUp or equivalent).

71-71: 일관성 없는 dp 사용

다른 화면들과 마찬가지로 screenWidthDp(24.dp)를 사용하여 반응형 레이아웃을 유지하세요.

♻️ 수정 제안
-                .padding(horizontal = 24.dp)
+                .padding(horizontal = screenWidthDp(24.dp))

screenWidthDp import도 추가해야 합니다:

import com.byeboo.app.core.util.screenWidthDp
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`
at line 71, Replace the hard-coded horizontal padding call in MyAnswerScreen
(the .padding(horizontal = 24.dp) usage) with the responsive helper
screenWidthDp(24.dp) and add the import com.byeboo.app.core.util.screenWidthDp;
update the padding invocation to .padding(horizontal = screenWidthDp(24.dp)) so
the layout becomes responsive and consistent with other screens.

59-60: MyAnswerScreenprivate으로 변경 권장

Route/Screen 패턴에서 Screen 컴포저블은 일반적으로 private으로 선언하여 외부에서 직접 호출되지 않도록 합니다. QuestReviewScreen.ktCommonAnswerScreen.kt의 패턴과 일치시키세요.

♻️ 수정 제안
 `@Composable`
-fun MyAnswerScreen(
+private fun MyAnswerScreen(
     uiState: MyAnswerState,
     onMyAnswerContentClick: (Long) -> Unit,
     paddingValues: PaddingValues,
     modifier: Modifier = Modifier,
 ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`
around lines 59 - 60, MyAnswerScreen is declared public but should follow the
Route/Screen pattern and be made private; change the function declaration from
"fun MyAnswerScreen(...)" to "private fun MyAnswerScreen(...)" and ensure any
calls are internal to the file (aligning with how QuestReviewScreen and
CommonAnswerScreen are scoped) so the composable cannot be invoked externally.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt (2)

77-77: 일관성 없는 dp 사용

다른 화면들에서는 screenWidthDp(24.dp)를 사용하는데, 여기서는 raw 24.dp를 직접 사용하고 있습니다. 반응형 레이아웃을 위해 일관된 유틸리티 함수 사용을 권장합니다.

♻️ 수정 제안
-                .padding(horizontal = 24.dp)
+                .padding(horizontal = screenWidthDp(24.dp))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`
at line 77, CommonAnswerScreen uses a hardcoded horizontal padding
".padding(horizontal = 24.dp)" which is inconsistent with other screens; replace
the raw 24.dp with the responsive utility call "screenWidthDp(24.dp)" inside the
CommonAnswerScreen composable so the padding becomes responsive and consistent
with other screens.

87-92: 하드코딩된 더미 데이터 - 서버 연결 시 교체 필요

QuestTitlestepNumber, questNumber, createdAt, questQuestion이 하드코딩되어 있습니다. PR 설명에 따르면 UI 확인용 더미 데이터로 의도된 것이지만, 실제 배포 전에 uiState에서 데이터를 가져오도록 변경해야 합니다.

서버 연결 시 이 부분을 uiState에서 데이터를 받아오도록 변경하는 것을 도와드릴까요?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`
around lines 87 - 92, The UI is using hardcoded dummy props for QuestTitle;
replace those literals by reading from the view state (uiState) instead: pass
uiState.<questField> values (e.g., uiState.currentQuest or uiState.quest's
stepNumber, questNumber, createdAt, and questQuestion) into QuestTitle, handling
nullability/defaults (safe calls, elvis operator or placeholder text) so the
composable renders real data from uiState rather than fixed dummy values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Line 18: The import for hiltViewModel is pointing to the wrong package;
replace the incorrect import line in CommonAnswerScreen.kt (the hiltViewModel
import) with the same package used across the codebase:
androidx.hilt.navigation.compose.hiltViewModel so it matches other files like
SplashScreen.kt and MainScreen.kt and aligns with the declared dependency
androidx.hilt:hilt-navigation-compose:1.3.0.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.kt`:
- Around line 61-68: The current branch for OtherPostOption.BLOCK emits
CommonAnswerSideEffect.NavigateToQuest before emitting the ShowSnackBar, which
can cause the snack bar to never appear after navigation; swap the emission
order so _sideEffect.emit(CommonAnswerSideEffect.ShowSnackBar(...)) is called
before _sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest) (refer to
OtherPostOption.BLOCK, _sideEffect.emit, CommonAnswerSideEffect.ShowSnackBar,
and CommonAnswerSideEffect.NavigateToQuest) to ensure the snack is shown prior
to navigation.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`:
- Around line 19-23: AnswerDetailTopBar currently exposes only
onClickMoreOptions and lacks a back-action callback, so the back icon does
nothing; add a new parameter onClickBack: () -> Unit to the AnswerDetailTopBar
composable signature and wire it to the back icon's click handler inside the
function (replace the TODO/no-op there to call onClickBack); update any call
sites of AnswerDetailTopBar to pass a suitable lambda (e.g.,
navController::popBackStack or equivalent) so the back icon performs navigation.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`:
- Around line 73-75: MyAnswerDetailScreen currently only wires
onClickMoreOptions to AnswerDetailTopBar so the back action is missing; update
MyAnswerDetailRoute -> MyAnswerDetailScreen -> AnswerDetailTopBar chain to
accept and forward a back callback (e.g., onBack or onClickBack) and invoke the
navigation back action (popBackStack()) from the route. Specifically, add an
onBack parameter to MyAnswerDetailRoute, pass it into MyAnswerDetailScreen,
forward that to AnswerDetailTopBar, and ensure AnswerDetailTopBar calls the
provided callback when the back icon is pressed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`:
- Line 26: The import for hiltViewModel in MyAnswerScreen.kt is incorrect;
replace the incorrect import
androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel with the correct compose
Hilt import androidx.hilt.navigation.compose.hiltViewModel so usages of
hiltViewModel within the MyAnswerScreen composable (or any functions referencing
hiltViewModel) resolve correctly and the module compiles.

---

Duplicate comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.kt`:
- Around line 6-16: The default profileIconRes = 0 is invalid and can throw
Resources.NotFoundException; update CommonAnswerModel.profileIconRes to be safe
by either making it nullable (Int? = null) and adjust all UI consumers to handle
null (e.g., show placeholder when profileIconRes == null) or assign a valid
drawable default (e.g., DEFAULT_PROFILE_ICON) and use that constant in
CommonAnswerState's initializer; touch the CommonAnswerModel declaration and
every place that reads profileIconRes (adapter/binding/Composables) to implement
the chosen null/placeholder handling.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`:
- Line 59: The code crashes when uiState.answers is empty because
MyAnswerDetailScreen uses uiState.answers.first(); change this to safe access
(e.g., use firstOrNull() or check isEmpty()) and handle the null/empty case
before proceeding: update the answerState assignment to use firstOrNull() and
add a guard (early return, placeholder UI, or error state) in the
MyAnswerDetailScreen rendering logic so downstream code does not assume a
non-null answer.

---

Nitpick comments:
In
`@app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt`:
- Around line 6-20: Update the SUCCESS subtype to accept an optional icon
parameter so callers can override the icon; change the SUCCESS constructor
signature in CustomSnackBarType to include a `@DrawableRes` icon: Int =
R.drawable.ic_success (or similar default) and pass that icon into the sealed
class primary constructor when constructing SUCCESS, leaving the message
parameter as-is to preserve existing usage.
- Around line 10-13: The ALERT case in CustomSnackBarType currently hardcodes
the message string; add a string resource (e.g., snackbar_server_error) to
strings.xml and stop embedding raw text in CustomSnackBarType.ALERT by either
(A) changing the sealed class to accept a messageResId Int (e.g., add a
parameter messageResId: Int? alongside icon) and set ALERT to messageResId =
R.string.snackbar_server_error, or (B) leave the sealed class unchanged but
remove the hardcoded message (set message = null or empty) and update the
CustomSnackBar composable to resolve the appropriate string via
LocalContext.current.getString(R.string.snackbar_server_error) when rendering
ALERT; pick one approach and apply it consistently (update constructors/usages
of CustomSnackBarType, the ALERT object, and the CustomSnackBar composable to
load the string resource).

In
`@app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.kt`:
- Line 66: BlockedUsersScreen currently ignores UiState.Failure (is
UiState.Failure -> Unit); update the BlockedUsersScreen composable to handle
UiState.Failure by surfacing the error (e.g., show a Snackbar via
Scaffold/rememberSnackbarHostState or render an error UI) and pass the failure
message from the UiState.Failure instance into that UI; modify the state
handling branch that matches UiState.Failure to call
snackbarHostState.showSnackbar(...) or render an ErrorView and ensure the
ViewModel/UiState provides the failure message used for display.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt`:
- Around line 83-90: HorizontalDivider currently uses
Modifier.padding(screenHeightDp(20.dp)) which applies padding on all sides;
change it to use vertical padding only so only top/bottom spacing is affected —
update the modifier on HorizontalDivider (the call that currently uses
Modifier.fillMaxWidth().padding(screenHeightDp(20.dp))) to use
Modifier.fillMaxWidth().padding(vertical = screenHeightDp(20.dp)) so left/right
padding is not applied.

In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt`:
- Around line 85-93: The callback name for "my answers" must be renamed to match
the ViewModel change: replace all occurrences of onMyAnswersClick with
onMyAnswersClicked — update the QuestScreen composable parameter name
(QuestScreen(... onMyAnswersClicked: () -> Unit ...)), the call site wiring (use
viewModel::onMyAnswersClicked instead of viewModel::onMyAnswersClick), and any
internal uses/forwarding of onMyAnswersClick (including navigate/handler
passthroughs) to the new onMyAnswersClicked identifier so names are consistent
with onQuestClicked and onTipClicked.

In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt`:
- Around line 289-293: Rename the ViewModel method onMyAnswersClick to
onMyAnswersClicked and update all its usages/call sites accordingly (including
any references in XML, navigation, tests, and callers) to keep naming consistent
with onTipClicked and onQuestClicked; preserve the implementation (launching
viewModelScope and emitting QuestSideEffect.NavigateToQuestMyAnswers) and update
any imports or overrides if applicable so compilation remains clean.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt`:
- Line 77: CommonAnswerScreen uses a hardcoded horizontal padding
".padding(horizontal = 24.dp)" which is inconsistent with other screens; replace
the raw 24.dp with the responsive utility call "screenWidthDp(24.dp)" inside the
CommonAnswerScreen composable so the padding becomes responsive and consistent
with other screens.
- Around line 87-92: The UI is using hardcoded dummy props for QuestTitle;
replace those literals by reading from the view state (uiState) instead: pass
uiState.<questField> values (e.g., uiState.currentQuest or uiState.quest's
stepNumber, questNumber, createdAt, and questQuestion) into QuestTitle, handling
nullability/defaults (safe calls, elvis operator or placeholder text) so the
composable renders real data from uiState rather than fixed dummy values.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt`:
- Around line 88-91: The no-op click handler on the back icon is left as a TODO;
wire up proper navigation by adding a navigateUp: () -> Unit parameter to
MyAnswerRoute (and propagate it into MyAnswerScreen), then replace the empty
lambda passed to Modifier.noRippleClickable with a call to that navigateUp
callback so the back icon triggers navigation (ensure MyAnswerRoute caller
supplies navController::navigateUp or equivalent).
- Line 71: Replace the hard-coded horizontal padding call in MyAnswerScreen (the
.padding(horizontal = 24.dp) usage) with the responsive helper
screenWidthDp(24.dp) and add the import com.byeboo.app.core.util.screenWidthDp;
update the padding invocation to .padding(horizontal = screenWidthDp(24.dp)) so
the layout becomes responsive and consistent with other screens.
- Around line 59-60: MyAnswerScreen is declared public but should follow the
Route/Screen pattern and be made private; change the function declaration from
"fun MyAnswerScreen(...)" to "private fun MyAnswerScreen(...)" and ensure any
calls are internal to the file (aligning with how QuestReviewScreen and
CommonAnswerScreen are scoped) so the composable cannot be invoked externally.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`:
- Around line 81-90: The onOptionClicked function currently wraps empty TODO
branches in viewModelScope.launch and should be simplified or implemented: if
you don't yet have async work, remove the unnecessary coroutine wrapper and
directly call onDismissBottomSheet and the synchronous handlers for
MyPostOption.EDIT and MyPostOption.DELETE; if you intend to implement behavior
now, replace the TODOs inside onOptionClicked (handling MyPostOption.EDIT to
navigate/open edit screen and MyPostOption.DELETE to show a delete confirmation
modal) and only keep viewModelScope.launch if those handlers perform suspend
work (network/DB); reference the onOptionClicked function and MyPostOption enum
to locate and update the branches accordingly.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eebf0ca and 5348a26.

📒 Files selected for processing (73)
  • app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBar.kt
  • app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt
  • app/src/main/java/com/byeboo/app/core/designsystem/event/SnackbarTrigger.kt
  • app/src/main/java/com/byeboo/app/core/designsystem/type/CustomSnackBarType.kt
  • app/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoState.kt
  • app/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/home/HomeScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/home/HomeUiState.kt
  • app/src/main/java/com/byeboo/app/presentation/home/HomeViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletState.kt
  • app/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/main/MainScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/MyPageScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/MyPageState.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/MypageViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/blockedusers/BlockedUsersState.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileState.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/OffboardingJourneyState.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/OffboardingJourneyViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideState.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedjourney/OffboardingCompletedJourneyScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedState.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorWritingScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/bottomsheet/MoreOptionsBottomSheet.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/card/CommonAnswerItem.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/type/OptionType.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/splash/SplashScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/splash/SplashState.kt
  • app/src/main/java/com/byeboo/app/presentation/splash/SplashViewModel.kt
🚧 Files skipped from review as they are similar to previous changes (28)
  • app/src/main/java/com/byeboo/app/presentation/splash/SplashScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/MyPageState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/component/card/MyAnswerItem.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipViewModel.kt
  • app/src/main/java/com/byeboo/app/core/designsystem/event/SnackbarTrigger.kt
  • app/src/main/java/com/byeboo/app/presentation/home/HomeScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewScreen.kt
  • app/src/main/java/com/byeboo/app/core/designsystem/component/snackbar/CustomSnackBarVisuals.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideState.kt
  • app/src/main/java/com/byeboo/app/presentation/home/homeamulet/HomeAmuletState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingState.kt
  • app/src/main/java/com/byeboo/app/presentation/auth/userinfo/UserInfoViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestcompleted/OffboardingQuestCompletedViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingquestreview/OffboardingQuestReviewState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerState.kt
  • app/src/main/java/com/byeboo/app/presentation/home/HomeViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/tip/QuestTipScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedjourney/OffboardingCompletedJourneyScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/QuestBehaviorCompleteScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewState.kt
  • app/src/main/java/com/byeboo/app/presentation/offboarding/offboardingcompletedguide/OffboardingCompletedGuideScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/mypage/editprofile/EditProfileScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/start/QuestStartScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/splash/SplashViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/QuestRecordingCompleteViewModel.kt

Comment on lines +61 to +68
OtherPostOption.BLOCK -> {
_sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest)
_sideEffect.emit(
CommonAnswerSideEffect.ShowSnackBar(
snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."),
),
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

사이드 이펙트 순서 확인 필요: 스낵바가 표시되지 않을 수 있습니다.

NavigateToQuestShowSnackBar보다 먼저 emit되면, 화면 전환이 즉시 발생하여 스낵바가 사용자에게 표시되지 않을 수 있습니다. 의도한 동작인지 확인해 주세요.

💡 스낵바를 먼저 표시하는 제안
                     OtherPostOption.BLOCK -> {
+                        _sideEffect.emit(
+                            CommonAnswerSideEffect.ShowSnackBar(
+                                snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."),
+                            ),
+                        )
                         _sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest)
-                        _sideEffect.emit(
-                            CommonAnswerSideEffect.ShowSnackBar(
-                                snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."),
-                            ),
-                        )
                     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
OtherPostOption.BLOCK -> {
_sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest)
_sideEffect.emit(
CommonAnswerSideEffect.ShowSnackBar(
snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."),
),
)
}
OtherPostOption.BLOCK -> {
_sideEffect.emit(
CommonAnswerSideEffect.ShowSnackBar(
snackBarType = CustomSnackBarType.SUCCESS("차단이 완료되었어요. 이에 해당 사용자의 글이 노출되지 않아요."),
),
)
_sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.kt`
around lines 61 - 68, The current branch for OtherPostOption.BLOCK emits
CommonAnswerSideEffect.NavigateToQuest before emitting the ShowSnackBar, which
can cause the snack bar to never appear after navigation; swap the emission
order so _sideEffect.emit(CommonAnswerSideEffect.ShowSnackBar(...)) is called
before _sideEffect.emit(CommonAnswerSideEffect.NavigateToQuest) (refer to
OtherPostOption.BLOCK, _sideEffect.emit, CommonAnswerSideEffect.ShowSnackBar,
and CommonAnswerSideEffect.NavigateToQuest) to ensure the snack is shown prior
to navigation.

Comment on lines +19 to +23
@Composable
fun AnswerDetailTopBar(
onClickMoreOptions: () -> Unit,
modifier: Modifier = Modifier,
) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

뒤로 가기 콜백 파라미터 누락

AnswerDetailTopBaronClickMoreOptions 콜백은 있지만, 뒤로 가기 기능을 위한 onClickBack 콜백 파라미터가 없습니다. TODO 주석만 있고 실제 동작이 연결되지 않아 사용자가 뒤로 가기 아이콘을 탭해도 아무 동작도 하지 않습니다.

🔧 뒤로 가기 콜백 추가 제안
 `@Composable`
 fun AnswerDetailTopBar(
+    onClickBack: () -> Unit,
     onClickMoreOptions: () -> Unit,
     modifier: Modifier = Modifier,
 ) {
         Icon(
             imageVector = ImageVector.vectorResource(id = R.drawable.ic_left),
-            contentDescription = null,
+            contentDescription = "뒤로 가기",
             tint = ByeBooTheme.colors.gray50,
             modifier =
                 Modifier.noRippleClickable(
-                    // Todo: 뒤로가기
+                    onClick = onClickBack,
                 ),
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/component/AnswerDetailTopBar.kt`
around lines 19 - 23, AnswerDetailTopBar currently exposes only
onClickMoreOptions and lacks a back-action callback, so the back icon does
nothing; add a new parameter onClickBack: () -> Unit to the AnswerDetailTopBar
composable signature and wire it to the back icon's click handler inside the
function (replace the TODO/no-op there to call onClickBack); update any call
sites of AnswerDetailTopBar to pass a suitable lambda (e.g.,
navController::popBackStack or equivalent) so the back icon performs navigation.

Comment on lines +73 to +75
AnswerDetailTopBar(
onClickMoreOptions = onClickMoreOptions,
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

상단 뒤로가기 동작이 연결되지 않아 탐색 흐름이 끊깁니다.

현재 상세 화면 상단바는 더보기만 연결되어 있고, 뒤로가기 아이콘 경로는 연결되지 않은 상태입니다. 이 화면 진입 후 상단 UI로는 이전 화면 복귀가 불가능합니다.

필요하시면 MyAnswerDetailRoute/MyAnswerDetailScreen/AnswerDetailTopBar까지 포함해 뒤로가기 콜백 연결 diff를 한 번에 정리해드리겠습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerDetailScreen.kt`
around lines 73 - 75, MyAnswerDetailScreen currently only wires
onClickMoreOptions to AnswerDetailTopBar so the back action is missing; update
MyAnswerDetailRoute -> MyAnswerDetailScreen -> AnswerDetailTopBar chain to
accept and forward a back callback (e.g., onBack or onClickBack) and invoke the
navigation back action (popBackStack()) from the route. Specifically, add an
onBack parameter to MyAnswerDetailRoute, pass it into MyAnswerDetailScreen,
forward that to AnswerDetailTopBar, and ensure AnswerDetailTopBar calls the
provided callback when the back icon is pressed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.kt (1)

1-1: ⚠️ Potential issue | 🟠 Major

패키지 선언 수정 필요

이 파일의 패키지 선언이 파일 위치와 일치하지 않습니다. 파일은 quest/review/my/ 디렉토리에 있지만, 현재 패키지는 com.byeboo.app.presentation.quest.review로 선언되어 있습니다. 동일 디렉토리의 다른 파일들(QuestReviewState.kt, QuestReviewViewModel.kt)은 올바르게 com.byeboo.app.presentation.quest.review.my로 선언되어 있습니다.

패키지 선언을 com.byeboo.app.presentation.quest.review.my로 수정하세요. 그러면 lines 50-52의 명시적 임포트는 불필요해집니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.kt`
at line 1, Update the package declaration in QuestReviewScreen.kt from
com.byeboo.app.presentation.quest.review to
com.byeboo.app.presentation.quest.review.my so it matches the file directory and
sibling files (e.g., QuestReviewState, QuestReviewViewModel), and then remove
the now-unnecessary explicit imports referenced around lines 50-52 (they become
redundant after the package fix).
🧹 Nitpick comments (5)
app/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteScreen.kt (1)

148-148: TODO 코멘트가 남아있습니다.

AI 버튼 연결이 아직 구현되지 않았습니다. PR 설명에 "추후 반영 예정"으로 언급되어 있으니 이슈로 추적하시겠습니까?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteScreen.kt`
at line 148, The onClick for the AI button in QuestRecordingCompleteScreen.kt
currently contains a lingering TODO; replace the placeholder in the Composable
where onClick = { /*Todo: ai 버튼 연결 */ } (in QuestRecordingCompleteScreen) by
either wiring the real handler (call the ViewModel action or navigation method,
e.g., viewModel.onAiButtonClicked() or navController.navigate(...) used
elsewhere) or, if not implementing now, create a tracked issue and replace the
TODO with a clear placeholder that references that issue (e.g., onClick = { /*
TODO: see ISSUE-1234 */ }) so the intent is traceable and the code no longer
contains an untracked TODO.
app/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingViewModel.kt (1)

205-205: getQuestRecordedDetail 호출 결과가 무시되고 있습니다.

이 호출이 캐시 갱신 목적이라면 의도가 명확하지 않습니다. 결과를 사용하지 않는다면 주석을 추가하거나, 실패 시 처리가 필요한지 검토해 주세요.

💡 의도를 명확히 하는 제안
-                        questRecordedDetailRepository.getQuestRecordedDetail(questId)
+                        // 캐시 갱신을 위한 호출 - 결과는 사용하지 않음
+                        questRecordedDetailRepository.getQuestRecordedDetail(questId)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingViewModel.kt`
at line 205, getQuestRecordedDetail 호출의 반환값이 전혀 사용되지 않아 결과(성공/실패/데이터)를 무시하고
있습니다; questRecordedDetailRepository.getQuestRecordedDetail(questId)의 결과를 활용하거나
의도를 명확히 하세요 — 실제로 캐시 갱신 용도라면 해당 호출을 비동기 작업(viewModelScope 등)으로 감싸고 실패 시 로깅 또는
retry/에러 처리 로직을 추가하거나, 반환값을 사용해 UI 상태를 갱신하도록 수정하고(예: 응답을 변수에 할당하거나 콜백/Flow로 처리),
단순히 무시하는 경우엔 이유를 설명하는 주석을 getQuestRecordedDetail 호출 위에 남기고 예외/에러를 최소한 로깅하도록
변경하세요.
app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt (1)

240-240: 사용되지 않는 repository 호출 결과

questRecordedDetailRepository.getQuestRecordedDetail(questId) 호출 결과가 사용되지 않습니다. 캐시 갱신이나 사이드 이펙트 목적이라면 주석으로 의도를 명시하거나, 불필요하다면 제거하세요.

-                questRecordedDetailRepository.getQuestRecordedDetail(questId)
+                // 캐시 갱신을 위해 호출 (결과 사용하지 않음)
+                questRecordedDetailRepository.getQuestRecordedDetail(questId)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`
at line 240, The call to
questRecordedDetailRepository.getQuestRecordedDetail(questId) in
QuestBehaviorViewModel is ignored — either consume its result, remove it, or
document its side-effect intent; fix by (a) assigning the returned value to a
variable and using it (e.g., update LiveData/state or handle errors) if the data
is needed, (b) remove the call if it’s unnecessary, or (c) keep the call but add
a clear comment explaining the intentional side-effect (cache refresh) and
handle errors/logging in the surrounding function so the intent and any failures
are explicit.
app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt (1)

187-194: onAnswerClick 콜백이 연결되지 않았습니다.

onAnswerClick 파라미터가 선언되었지만 CommonAnswerItemonClick에 연결되지 않았습니다. PR 목표에 "네비게이션 연결"이 미완료 항목으로 명시되어 있으니, TODO를 명확히 남기거나 실제 연결을 구현하세요.

💡 연결 구현 예시
 CommonAnswerItem(
     answer = answer,
-    onClick = { /* Todo: 네비 연결 */ },
+    onClick = { onAnswerClick(answer.answerId) },
     modifier =

구현을 도와드릴까요, 아니면 추적을 위한 이슈를 생성할까요?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt`
around lines 187 - 194, The CommonJourneyScreen currently passes a lambda TODO
to CommonAnswerItem's onClick instead of wiring the declared onAnswerClick
callback; update the CommonAnswerItem invocation in CommonJourneyScreen (the
call site inside CommonAnswerItem(...)) to pass the onAnswerClick parameter
(e.g., onClick = { onAnswerClick(answer) }) so the screen uses the provided
callback, or if navigation is intentionally deferred replace the TODO with a
clear TODO comment referencing onAnswerClick (e.g., // TODO: call
onAnswerClick(answer) to navigate) so intent is explicit; locate
CommonAnswerItem usage in CommonJourneyScreen.kt and modify its onClick argument
accordingly.
app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt (1)

95-95: 네비게이션 패턴 일관성 검토

다른 클릭 핸들러들(onQuestClick, onMyAnswersClick)은 ViewModel을 통해 Side Effect로 네비게이션을 처리하지만, onCommonAnswerClicknavigateToCommonAnswer를 직접 전달하고 있습니다.

일관성을 위해 ViewModel에서 Side Effect를 발생시키는 패턴으로 통일하는 것을 고려해 주세요.

♻️ 일관된 패턴 적용 예시

QuestRoute에서:

-        onCommonAnswerClick = navigateToCommonAnswer,
+        onCommonAnswerClick = viewModel::onCommonAnswerClicked,

QuestSideEffect에 추가:

data class NavigateToCommonAnswer(val answerId: Long) : QuestSideEffect

Side Effect 처리에 추가:

is QuestSideEffect.NavigateToCommonAnswer ->
    navigateToCommonAnswer(effect.answerId)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt` at line
95, onCommonAnswerClick is currently wired directly to navigateToCommonAnswer,
breaking the established pattern where onQuestClick and onMyAnswersClick emit
navigation via QuestViewModel side effects; change onCommonAnswerClick to call a
ViewModel handler that emits a new side effect (add
QuestSideEffect.NavigateToCommonAnswer(answerId)), update QuestViewModel to emit
that side effect instead of performing navigation, and update the side-effect
consumer (where QuestSideEffect is handled) to react to
QuestSideEffect.NavigateToCommonAnswer by calling
navigateToCommonAnswer(effect.answerId) so all navigation flows consistently
through the ViewModel.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/main/java/com/byeboo/app/presentation/main/MainNavHost.kt`:
- Around line 142-156: 현재 navigateToQuestCommonAnswer, navigateToQuestMyAnswers,
navigateToQuestMyAnswerDetail에서 상세 화면으로 이동할 때 clearStackNavOptions를 사용해 네비게이션 스택
전체를 삭제하고 있어 뒤로가기 불가능 상태가 됩니다; 의도한 동작이 아니라면 이 세 곳에서 clearStackNavOptions 대신
keepStackNavOptions를 사용하도록 수정하여 기존 스택을 유지하고 뒤로가기를 허용하세요 (참조 심볼:
navigateToQuestCommonAnswer, navigateToQuestMyAnswers,
navigateToQuestMyAnswerDetail, clearStackNavOptions, keepStackNavOptions).

In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`:
- Around line 214-216: The runCatching block that calls
context.contentResolver.openInputStream(imageUrl) is leaking the InputStream;
apply the same fix here as in uploadEditedImage(): wrap the result of
openInputStream(...) in a Kotlin use { } scope (or ensure finally closes the
stream) so the InputStream is always closed after reading bytes, e.g., replace
direct readBytes() on inputStream with inputStream.use { it.readBytes() } within
the runCatching in the function containing the current code and do the same in
uploadEditedImage().
- Around line 143-146: The runCatching block in QuestBehaviorViewModel opens an
InputStream via context.contentResolver.openInputStream(imageUrl) but never
closes it, risking resource leaks; modify the code that reads the stream (the
inputStream and imageBytes logic inside the runCatching) to use the Kotlin use {
} extension on the stream (e.g.,
context.contentResolver.openInputStream(imageUrl)?.use { /* readBytes and derive
contentType */ } ) so the stream is always closed even on exceptions, preserving
existing error handling around imageBytes and contentType retrieval.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt`:
- Around line 123-128: The route is ignoring the answerId passed via navigation:
QuestCommonAnswer navigates with an answerId but CommonAnswerRoute does not
accept it and CommonAnswerViewModel hardcodes loadCommonAnswer(1L). Fix by
wiring the param through either (A) inject SavedStateHandle into
CommonAnswerViewModel and read answerId from it (use key "answerId") so
loadCommonAnswer uses the extracted value instead of 1L, or (B) change
CommonAnswerRoute signature to accept an answerId parameter and forward that to
CommonAnswerViewModel (or call loadCommonAnswer(answerId)) when initializing;
update where CommonAnswerRoute is invoked in QuestNavigation to pass the
argument accordingly.

In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt`:
- Line 90: The onCommonQuestClick handler in QuestScreen (the onCommonQuestClick
lambda) is currently an empty lambda so common-quest taps do nothing; replace
the empty lambda with a call into the appropriate ViewModel method (e.g.,
viewModel.onCommonQuestClicked(questId) or navigation handler) or, if you cannot
implement now, add a clear TODO comment and create a tracked issue referencing
QuestScreen.onCommonQuestClick to implement the navigation/logic later; ensure
the handler forwards necessary identifiers (quest id or model) and
updates/navigation are performed via the ViewModel/Navigation component rather
than handling UI logic inline.

---

Outside diff comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.kt`:
- Line 1: Update the package declaration in QuestReviewScreen.kt from
com.byeboo.app.presentation.quest.review to
com.byeboo.app.presentation.quest.review.my so it matches the file directory and
sibling files (e.g., QuestReviewState, QuestReviewViewModel), and then remove
the now-unnecessary explicit imports referenced around lines 50-52 (they become
redundant after the package fix).

---

Nitpick comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`:
- Line 240: The call to
questRecordedDetailRepository.getQuestRecordedDetail(questId) in
QuestBehaviorViewModel is ignored — either consume its result, remove it, or
document its side-effect intent; fix by (a) assigning the returned value to a
variable and using it (e.g., update LiveData/state or handle errors) if the data
is needed, (b) remove the call if it’s unnecessary, or (c) keep the call but add
a clear comment explaining the intentional side-effect (cache refresh) and
handle errors/logging in the surrounding function so the intent and any failures
are explicit.

In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt`:
- Line 95: onCommonAnswerClick is currently wired directly to
navigateToCommonAnswer, breaking the established pattern where onQuestClick and
onMyAnswersClick emit navigation via QuestViewModel side effects; change
onCommonAnswerClick to call a ViewModel handler that emits a new side effect
(add QuestSideEffect.NavigateToCommonAnswer(answerId)), update QuestViewModel to
emit that side effect instead of performing navigation, and update the
side-effect consumer (where QuestSideEffect is handled) to react to
QuestSideEffect.NavigateToCommonAnswer by calling
navigateToCommonAnswer(effect.answerId) so all navigation flows consistently
through the ViewModel.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteScreen.kt`:
- Line 148: The onClick for the AI button in QuestRecordingCompleteScreen.kt
currently contains a lingering TODO; replace the placeholder in the Composable
where onClick = { /*Todo: ai 버튼 연결 */ } (in QuestRecordingCompleteScreen) by
either wiring the real handler (call the ViewModel action or navigation method,
e.g., viewModel.onAiButtonClicked() or navController.navigate(...) used
elsewhere) or, if not implementing now, create a tracked issue and replace the
TODO with a clear placeholder that references that issue (e.g., onClick = { /*
TODO: see ISSUE-1234 */ }) so the intent is traceable and the code no longer
contains an untracked TODO.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingViewModel.kt`:
- Line 205: getQuestRecordedDetail 호출의 반환값이 전혀 사용되지 않아 결과(성공/실패/데이터)를 무시하고 있습니다;
questRecordedDetailRepository.getQuestRecordedDetail(questId)의 결과를 활용하거나 의도를 명확히
하세요 — 실제로 캐시 갱신 용도라면 해당 호출을 비동기 작업(viewModelScope 등)으로 감싸고 실패 시 로깅 또는 retry/에러
처리 로직을 추가하거나, 반환값을 사용해 UI 상태를 갱신하도록 수정하고(예: 응답을 변수에 할당하거나 콜백/Flow로 처리), 단순히 무시하는
경우엔 이유를 설명하는 주석을 getQuestRecordedDetail 호출 위에 남기고 예외/에러를 최소한 로깅하도록 변경하세요.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt`:
- Around line 187-194: The CommonJourneyScreen currently passes a lambda TODO to
CommonAnswerItem's onClick instead of wiring the declared onAnswerClick
callback; update the CommonAnswerItem invocation in CommonJourneyScreen (the
call site inside CommonAnswerItem(...)) to pass the onAnswerClick parameter
(e.g., onClick = { onAnswerClick(answer) }) so the screen uses the provided
callback, or if navigation is intentionally deferred replace the TODO with a
clear TODO comment referencing onAnswerClick (e.g., // TODO: call
onAnswerClick(answer) to navigate) so intent is explicit; locate
CommonAnswerItem usage in CommonJourneyScreen.kt and modify its onClick argument
accordingly.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5348a26 and 7bbf351.

📒 Files selected for processing (21)
  • app/src/main/java/com/byeboo/app/presentation/main/MainNavHost.kt
  • app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/complete/QuestBehaviorCompleteScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/complete/QuestBehaviorCompleteState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/complete/QuestBehaviorCompleteViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorWritingScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/common/navigation/QuestCommonNavigation.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/complete/QuestRecordingCompleteViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingState.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/record/writing/QuestRecordingViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/my/QuestReviewScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/screen/CommonJourneyScreen.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/src/main/java/com/byeboo/app/presentation/quest/QuestViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/model/QuestState.kt
  • app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt

Comment on lines +142 to +156
navigateToQuestCommonAnswer = { answerId ->
navigator.navigateToQuestCommonAnswer(
answerId = answerId,
navOptions = clearStackNavOptions,
)
},
navigateToQuestMyAnswers = {
navigator.navigateToQuestMyAnswers(navOptions = clearStackNavOptions)
},
navigateToQuestMyAnswerDetail = { answerId ->
navigator.navigateToQuestMyAnswerDetail(
answerId = answerId,
navOptions = clearStackNavOptions,
)
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

상세 화면 네비게이션에 clearStackNavOptions 사용 검토 필요

navigateToQuestCommonAnswer, navigateToQuestMyAnswers, navigateToQuestMyAnswerDetailclearStackNavOptions를 사용하면 전체 네비게이션 스택이 삭제됩니다. 이로 인해 사용자가 상세 화면에서 뒤로가기를 할 수 없게 됩니다.

다른 상세/편집 화면들(예: Line 109-115의 navigateToQuestRecordingEdit)은 keepStackNavOptions를 사용하여 뒤로가기를 지원합니다. 의도된 동작이 아니라면 keepStackNavOptions 사용을 권장합니다.

🛠️ 수정 제안
             navigateToQuestCommonAnswer = { answerId ->
                 navigator.navigateToQuestCommonAnswer(
                     answerId = answerId,
-                    navOptions = clearStackNavOptions,
+                    navOptions = keepStackNavOptions,
                 )
             },
             navigateToQuestMyAnswers = {
-                navigator.navigateToQuestMyAnswers(navOptions = clearStackNavOptions)
+                navigator.navigateToQuestMyAnswers(navOptions = keepStackNavOptions)
             },
             navigateToQuestMyAnswerDetail = { answerId ->
                 navigator.navigateToQuestMyAnswerDetail(
                     answerId = answerId,
-                    navOptions = clearStackNavOptions,
+                    navOptions = keepStackNavOptions,
                 )
             },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
navigateToQuestCommonAnswer = { answerId ->
navigator.navigateToQuestCommonAnswer(
answerId = answerId,
navOptions = clearStackNavOptions,
)
},
navigateToQuestMyAnswers = {
navigator.navigateToQuestMyAnswers(navOptions = clearStackNavOptions)
},
navigateToQuestMyAnswerDetail = { answerId ->
navigator.navigateToQuestMyAnswerDetail(
answerId = answerId,
navOptions = clearStackNavOptions,
)
},
navigateToQuestCommonAnswer = { answerId ->
navigator.navigateToQuestCommonAnswer(
answerId = answerId,
navOptions = keepStackNavOptions,
)
},
navigateToQuestMyAnswers = {
navigator.navigateToQuestMyAnswers(navOptions = keepStackNavOptions)
},
navigateToQuestMyAnswerDetail = { answerId ->
navigator.navigateToQuestMyAnswerDetail(
answerId = answerId,
navOptions = keepStackNavOptions,
)
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/byeboo/app/presentation/main/MainNavHost.kt` around
lines 142 - 156, 현재 navigateToQuestCommonAnswer, navigateToQuestMyAnswers,
navigateToQuestMyAnswerDetail에서 상세 화면으로 이동할 때 clearStackNavOptions를 사용해 네비게이션 스택
전체를 삭제하고 있어 뒤로가기 불가능 상태가 됩니다; 의도한 동작이 아니라면 이 세 곳에서 clearStackNavOptions 대신
keepStackNavOptions를 사용하도록 수정하여 기존 스택을 유지하고 뒤로가기를 허용하세요 (참조 심볼:
navigateToQuestCommonAnswer, navigateToQuestMyAnswers,
navigateToQuestMyAnswerDetail, clearStackNavOptions, keepStackNavOptions).

Comment on lines 143 to 146
runCatching {
val inputStream = context.contentResolver.openInputStream(imageUrl)
val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.")
val contentType = context.contentResolver.getType(imageUrl).toString()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

InputStream 리소스 누수 가능성

openInputStream()으로 열린 스트림이 명시적으로 닫히지 않습니다. 예외 발생 시 리소스가 누수될 수 있습니다. .use {} 블록을 사용하여 스트림을 자동으로 닫도록 수정하세요.

🐛 리소스 누수 수정 제안
 runCatching {
-    val inputStream = context.contentResolver.openInputStream(imageUrl)
-    val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.")
+    val imageBytes = context.contentResolver.openInputStream(imageUrl)?.use { inputStream ->
+        inputStream.readBytes()
+    } ?: error("이미지 파일을 읽을 수 없습니다.")
     val contentType = context.contentResolver.getType(imageUrl).toString()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
runCatching {
val inputStream = context.contentResolver.openInputStream(imageUrl)
val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.")
val contentType = context.contentResolver.getType(imageUrl).toString()
runCatching {
val imageBytes = context.contentResolver.openInputStream(imageUrl)?.use { inputStream ->
inputStream.readBytes()
} ?: error("이미지 파일을 읽을 수 없습니다.")
val contentType = context.contentResolver.getType(imageUrl).toString()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`
around lines 143 - 146, The runCatching block in QuestBehaviorViewModel opens an
InputStream via context.contentResolver.openInputStream(imageUrl) but never
closes it, risking resource leaks; modify the code that reads the stream (the
inputStream and imageBytes logic inside the runCatching) to use the Kotlin use {
} extension on the stream (e.g.,
context.contentResolver.openInputStream(imageUrl)?.use { /* readBytes and derive
contentType */ } ) so the stream is always closed even on exceptions, preserving
existing error handling around imageBytes and contentType retrieval.

Comment on lines 214 to 216
runCatching {
val inputStream = context.contentResolver.openInputStream(imageUrl)
val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

동일한 InputStream 리소스 누수 문제

uploadEditedImage()에서도 동일하게 openInputStream()의 결과가 닫히지 않습니다.

🐛 수정 제안
 runCatching {
-    val inputStream = context.contentResolver.openInputStream(imageUrl)
-    val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.")
+    val imageBytes = context.contentResolver.openInputStream(imageUrl)?.use { inputStream ->
+        inputStream.readBytes()
+    } ?: error("이미지 파일을 읽을 수 없습니다.")
     val contentType = context.contentResolver.getType(imageUrl).toString()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`
around lines 214 - 216, The runCatching block that calls
context.contentResolver.openInputStream(imageUrl) is leaking the InputStream;
apply the same fix here as in uploadEditedImage(): wrap the result of
openInputStream(...) in a Kotlin use { } scope (or ensure finally closes the
stream) so the InputStream is always closed after reading bytes, e.g., replace
direct readBytes() on inputStream with inputStream.use { it.readBytes() } within
the runCatching in the function containing the current code and do the same in
uploadEditedImage().

Comment on lines 123 to 128
composable<QuestCommonAnswer> {
CommonAnswerRoute(
navigateToQuest = navigateToQuest,
paddingValues = paddingValues,
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's examine the QuestNavigation.kt file around the mentioned lines
cd /
find . -name "QuestNavigation.kt" -type f 2>/dev/null | head -5

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 176


🏁 Script executed:

#!/bin/bash
# Also search for CommonAnswerRoute and CommonAnswerViewModel definitions
fd -e kt -x rg -l "CommonAnswerRoute|CommonAnswerViewModel" {} + 2>/dev/null | head -20

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 349


🏁 Script executed:

#!/bin/bash
# Search for the QuestCommonAnswer route definition
rg "QuestCommonAnswer|@Serializable" --type=kotlin | head -30

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 3267


🏁 Script executed:

#!/bin/bash
# Check the QuestCommonAnswer data class definition
rg -A 5 "data class QuestCommonAnswer" app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestRoute.kt

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 188


🏁 Script executed:

#!/bin/bash
# Check the CommonAnswerViewModel for SavedStateHandle usage
cat -n app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerViewModel.kt

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 3631


🏁 Script executed:

#!/bin/bash
# Check CommonAnswerScreen.kt to find CommonAnswerRoute
cat -n app/src/main/java/com/byeboo/app/presentation/quest/review/common/all/CommonAnswerScreen.kt

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 4820


🏁 Script executed:

#!/bin/bash
# Check the QuestNavigation.kt file around the mentioned lines (120-135)
sed -n '110,140p' app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt

Repository: 36-APPJAM-HEARTZ/ByeBoo-ANDROID

Length of output: 1031


answerId 파라미터가 CommonAnswerViewModel에서 전혀 사용되지 않습니다.

QuestCommonAnswer(answerId)로 네비게이션하지만, CommonAnswerRoute는 이 파라미터를 받지 않으며, CommonAnswerViewModelSavedStateHandle을 사용하지 않습니다. 대신 loadCommonAnswer(1L)에서 answerId를 하드코딩하고 있어서 네비게이션할 때 전달한 answerId 값이 완전히 무시됩니다.

CommonAnswerViewModel 생성자에 SavedStateHandle을 주입하여 경로 인자에서 answerId를 추출하거나, CommonAnswerRoute를 통해 answerId를 명시적으로 전달하도록 수정이 필요합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/navigation/QuestNavigation.kt`
around lines 123 - 128, The route is ignoring the answerId passed via
navigation: QuestCommonAnswer navigates with an answerId but CommonAnswerRoute
does not accept it and CommonAnswerViewModel hardcodes loadCommonAnswer(1L). Fix
by wiring the param through either (A) inject SavedStateHandle into
CommonAnswerViewModel and read answerId from it (use key "answerId") so
loadCommonAnswer uses the extracted value instead of 1L, or (B) change
CommonAnswerRoute signature to accept an answerId parameter and forward that to
CommonAnswerViewModel (or call loadCommonAnswer(answerId)) when initializing;
update where CommonAnswerRoute is invoked in QuestNavigation to pass the
argument accordingly.

onCommonQuestClick = navigateToQuestCommon,
onQuestClick = viewModel::onQuestClicked,
onMyAnswersClick = viewModel::onMyAnswersClicked,
onCommonQuestClick = {/* 이동 관련 로직 뷰모델에 작성 */},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

미구현 로직: onCommonQuestClick 빈 람다

onCommonQuestClick이 빈 람다로 할당되어 있습니다. PR 설명의 미완료 작업 목록과 관련이 있는 것으로 보이나, 이 상태로 머지되면 공통 퀘스트 클릭 시 아무 동작도 하지 않습니다.

TODO 주석이나 별도 이슈로 추적하는 것을 권장합니다.

해당 로직 구현을 위한 이슈를 생성해 드릴까요?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt` at line
90, The onCommonQuestClick handler in QuestScreen (the onCommonQuestClick
lambda) is currently an empty lambda so common-quest taps do nothing; replace
the empty lambda with a call into the appropriate ViewModel method (e.g.,
viewModel.onCommonQuestClicked(questId) or navigation handler) or, if you cannot
implement now, add a clear TODO comment and create a tracked issue referencing
QuestScreen.onCommonQuestClick to implement the navigation/logic later; ensure
the handler forwards necessary identifiers (quest id or model) and
updates/navigation are performed via the ViewModel/Navigation component rather
than handling UI logic inline.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt (1)

133-139: ⚠️ Potential issue | 🟠 Major

업로드 로딩 상태가 해제되지 않아 UI가 고정될 수 있습니다.

onSaveClicked에서 isUploading = true 설정 후, 성공/실패 모두 false로 되돌리지 않고 있습니다. 또한 이미지가 없을 때 조기 반환되면 로딩 상태가 유지될 수 있습니다.

🔧 수정 제안
 fun onSaveClicked(context: Context) {
     viewModelScope.launch {
-        _uiState.update { it.copy(isUploading = true) }
-
         val state = _uiState.value
-        val imageUrl = state.selectedImageUri ?: return@launch
+        val imageUrl = state.selectedImageUri ?: return@launch
+        _uiState.update { it.copy(isUploading = true) }
         val questId = state.questId
         val answer = state.questAnswer
         val emotion = state.selectedEmotion?.toData().orEmpty()

         runCatching {
             val inputStream = context.contentResolver.openInputStream(imageUrl)
             val imageBytes = inputStream?.readBytes() ?: error("이미지 파일을 읽을 수 없습니다.")
             val contentType = context.contentResolver.getType(imageUrl).toString()
             val imageKey = UUID.randomUUID().toString()
@@
         }.onFailure {
             _sideEffect.emit(
                 QuestBehaviorSideEffect.ShowSnackBar(
                     snackBarType = CustomSnackBarType.ALERT,
                 ),
             )
         }
+        _uiState.update { it.copy(isUploading = false) }
     }
 }

Also applies to: 169-181

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`
around lines 133 - 139, onSaveClicked sets _uiState.isUploading = true but never
resets it on early return, success, or failure; wrap the upload/save logic in a
try/finally (or ensure all return paths) so that _uiState.update {
it.copy(isUploading = false) } runs on every exit, and handle the case where
selectedImageUri is null by clearing isUploading before returning; apply the
same fix to the other upload/save handler in this file (the analogous block
referenced at lines 169-181) so both handlers always clear the uploading flag.
♻️ Duplicate comments (1)
app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt (1)

90-90: ⚠️ Potential issue | 🟡 Minor

onCommonQuestClick가 no-op이라 공통 여정 퀘스트 탭 동작이 막혀 있습니다.

Line [90]에서 빈 람다를 넘겨 클릭 시 아무 처리도 실행되지 않습니다. 이 상태면 NavigateToQuestCommonWriting 분기도 실사용에서 트리거되지 않습니다.

🔧 수정 제안
-        onCommonQuestClick = { /* 이동 관련 로직 뷰모델에 작성 */ },
+        onCommonQuestClick = viewModel::onCommonQuestClicked,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt` at line
90, The onCommonQuestClick passed into QuestScreen is a no-op which prevents the
NavigateToQuestCommonWriting branch from ever being triggered; replace the empty
lambda with the view model navigation handler (or a lambda that calls the
navigation/event method) so clicks forward to NavigateToQuestCommonWriting.
Locate the QuestScreen call site where onCommonQuestClick is set and pass the
appropriate function from the corresponding ViewModel (e.g.,
viewModel::onCommonQuestClick or a lambda invoking
viewModel.navigateTo(NavigateToQuestCommonWriting)) ensuring the handler
emulates the same signature as onCommonQuestClick.
🧹 Nitpick comments (2)
app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt (1)

192-195: 공개 API 명칭 변경에는 임시 호환 레이어를 두는 것을 권장합니다.

기능은 정상으로 보입니다. 다만 병행 작업 브랜치가 많다면 기존 메서드명을 @Deprecated alias로 잠시 유지하면 머지 충돌과 호출부 일괄 수정 부담을 줄일 수 있습니다.

호환 alias 예시
+    `@Deprecated`(
+        message = "Use navigateToQuestCommonWriting(questId)",
+        replaceWith = ReplaceWith("navigateToQuestCommonWriting(questId)")
+    )
+    fun navigateToQuestCommon(questId: Long) {
+        navigateToQuestCommonWriting(questId)
+    }
+
     fun navigateToQuestCommonWriting(questId: Long) {
         navController.navigateToQuestCommonWriting(
             questId = questId,
         )
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt` around
lines 192 - 195, Add a temporary compatibility alias that preserves the old
public API name and delegates to the new function: declare a `@Deprecated`
annotated method (e.g., navigateToQuestWriting(questId: Long)) that simply calls
navigateToQuestCommonWriting(questId), so existing callers keep working while
you migrate call sites; mark it with a deprecation message and target
ReplaceWith pointing to navigateToQuestCommonWriting to guide callers to the new
API.
app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt (1)

30-69: init에서 더미 데이터를 고정 주입하는 구조는 분리하는 것이 안전합니다.

현재 구조는 실제 데이터 연동 시 교체 누락 위험이 있어, 더미 공급을 별도 provider/fake repository로 분리하거나 빌드/플래그 기반으로 제한하는 편이 좋습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`
around lines 30 - 69, The init block in MyAnswerViewModel directly injects test
data via getDummyAnswers(), which risks leftover dummy data in production;
refactor by extracting getDummyAnswers() into a separate FakeAnswersProvider or
a FakeAnswersRepository and add a constructor parameter (e.g., answersRepository
or initialAnswers: ImmutableList<MyAnswerModel>? = null) to MyAnswerViewModel so
production callers pass real data while tests/preview can pass the fake provider
or list; update init to use the injected repository/provider or the nullable
initialAnswers and remove hardcoded dummy injection from the view model.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`:
- Around line 85-96: The onOptionClicked handler currently does nothing for
MyPostOption.EDIT and MyPostOption.DELETE; update onOptionClicked in
MyAnswerViewModel to emit appropriate side effects (e.g.,
MyAnswerSideEffect.NavigateToEdit(postId) for EDIT and
MyAnswerSideEffect.ShowDeleteConfirmation(postId) for DELETE) via the
ViewModel's side-effect emitter (e.g., sideEffect/ _sideEffect/emit or send in
viewModelScope) so UI can navigate or open a delete modal; ensure you pass the
relevant identifier (postId) or payload and keep emissions inside the existing
viewModelScope.launch block.

---

Outside diff comments:
In
`@app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt`:
- Around line 133-139: onSaveClicked sets _uiState.isUploading = true but never
resets it on early return, success, or failure; wrap the upload/save logic in a
try/finally (or ensure all return paths) so that _uiState.update {
it.copy(isUploading = false) } runs on every exit, and handle the case where
selectedImageUri is null by clearing isUploading before returning; apply the
same fix to the other upload/save handler in this file (the analogous block
referenced at lines 169-181) so both handlers always clear the uploading flag.

---

Duplicate comments:
In `@app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt`:
- Line 90: The onCommonQuestClick passed into QuestScreen is a no-op which
prevents the NavigateToQuestCommonWriting branch from ever being triggered;
replace the empty lambda with the view model navigation handler (or a lambda
that calls the navigation/event method) so clicks forward to
NavigateToQuestCommonWriting. Locate the QuestScreen call site where
onCommonQuestClick is set and pass the appropriate function from the
corresponding ViewModel (e.g., viewModel::onCommonQuestClick or a lambda
invoking viewModel.navigateTo(NavigateToQuestCommonWriting)) ensuring the
handler emulates the same signature as onCommonQuestClick.

---

Nitpick comments:
In `@app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt`:
- Around line 192-195: Add a temporary compatibility alias that preserves the
old public API name and delegates to the new function: declare a `@Deprecated`
annotated method (e.g., navigateToQuestWriting(questId: Long)) that simply calls
navigateToQuestCommonWriting(questId), so existing callers keep working while
you migrate call sites; mark it with a deprecation message and target
ReplaceWith pointing to navigateToQuestCommonWriting to guide callers to the new
API.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`:
- Around line 30-69: The init block in MyAnswerViewModel directly injects test
data via getDummyAnswers(), which risks leftover dummy data in production;
refactor by extracting getDummyAnswers() into a separate FakeAnswersProvider or
a FakeAnswersRepository and add a constructor parameter (e.g., answersRepository
or initialAnswers: ImmutableList<MyAnswerModel>? = null) to MyAnswerViewModel so
production callers pass real data while tests/preview can pass the fake provider
or list; update init to use the injected repository/provider or the nullable
initialAnswers and remove hardcoded dummy injection from the view model.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bbf351 and f18548e.

📒 Files selected for processing (4)
  • app/src/main/java/com/byeboo/app/presentation/main/MainNavigator.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/QuestScreen.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/behavior/writing/QuestBehaviorViewModel.kt
  • app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt

Comment on lines 85 to 96
fun onOptionClicked(option: MyPostOption) {
onDismissBottomSheet()

viewModelScope.launch {
when (option) {
MyPostOption.EDIT -> { // TODO 수정 화면 이동
}

MyPostOption.DELETE -> { // TODO 삭제 모달 띄우기
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

옵션 클릭 처리(EDIT/DELETE)가 현재 no-op입니다.

분기 내부가 비어 있어 사용자 액션이 실제 기능으로 이어지지 않습니다. 머지 전 최소한 side effect emit(네비게이션/모달 트리거) 또는 UI에서 진입 차단이 필요합니다.

원하시면 MyAnswerSideEffect 확장 포함해서 EDIT/DELETE 동작 연결안(네비 + 삭제 모달 트리거) 바로 작성해드릴게요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/byeboo/app/presentation/quest/review/common/personal/MyAnswerViewModel.kt`
around lines 85 - 96, The onOptionClicked handler currently does nothing for
MyPostOption.EDIT and MyPostOption.DELETE; update onOptionClicked in
MyAnswerViewModel to emit appropriate side effects (e.g.,
MyAnswerSideEffect.NavigateToEdit(postId) for EDIT and
MyAnswerSideEffect.ShowDeleteConfirmation(postId) for DELETE) via the
ViewModel's side-effect emitter (e.g., sideEffect/ _sideEffect/emit or send in
viewModelScope) so UI can navigate or open a delete modal; ensure you pass the
relevant identifier (postId) or payload and keep emissions inside the existing
viewModelScope.launch block.

@sohee6989 sohee6989 merged commit a694124 into develop Mar 1, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🍒 [FEAT] 새로운 기능 구현 🍥 [UI] UI 작업 🐰 아연 아연

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[feat] 공통 여정 퀘스트 돌아보기

3 participants